presentation/RuleConsoleInput.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "RuleConsoleInput.h" | ||
| 2 | |||
| 3 | #include <QCoreApplication> | ||
| 4 | #include <QRegularExpression> | ||
| 5 | #include <QVariantList> | ||
| 6 | #include <algorithm> | ||
| 7 | |||
| 8 | namespace RuleConsoleInput { | ||
| 9 | |||
| 10 | namespace { | ||
| 11 | |||
| 12 | // Splits on whitespace; "quoted parts" stay together (quotes removed). | ||
| 13 | 64 | QStringList tokenize(const QString &text) { | |
| 14 | 64 | QStringList tokens; | |
| 15 | 64 | QString current; | |
| 16 | 64 | bool quoted = false; | |
| 17 | 64 | bool hadQuote = false; | |
| 18 |
2/2✓ Branch 26 → 4 taken 1168 times.
✓ Branch 26 → 27 taken 64 times.
|
1232 | for (const QChar c : text) { |
| 19 |
2/2✓ Branch 7 → 8 taken 28 times.
✓ Branch 7 → 9 taken 1140 times.
|
1168 | if (c == QLatin1Char('"')) { |
| 20 | 28 | quoted = !quoted; | |
| 21 | 28 | hadQuote = true; | |
| 22 | 28 | continue; | |
| 23 | } | ||
| 24 |
6/6✓ Branch 10 → 11 taken 94 times.
✓ Branch 10 → 13 taken 1046 times.
✓ Branch 11 → 12 taken 92 times.
✓ Branch 11 → 13 taken 2 times.
✓ Branch 14 → 15 taken 92 times.
✓ Branch 14 → 24 taken 1048 times.
|
1140 | if (c.isSpace() && !quoted) { |
| 25 |
5/6✓ Branch 16 → 17 taken 24 times.
✓ Branch 16 → 18 taken 68 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 24 times.
✓ Branch 20 → 21 taken 68 times.
✓ Branch 20 → 22 taken 24 times.
|
92 | if (!current.isEmpty() || hadQuote) |
| 26 |
1/1✓ Branch 21 → 22 taken 68 times.
|
68 | tokens.append(current); |
| 27 | 92 | current.clear(); | |
| 28 | 92 | hadQuote = false; | |
| 29 | 92 | continue; | |
| 30 | } | ||
| 31 |
1/1✓ Branch 24 → 25 taken 1048 times.
|
1048 | current.append(c); |
| 32 | } | ||
| 33 |
5/6✓ Branch 28 → 29 taken 40 times.
✓ Branch 28 → 30 taken 24 times.
✗ Branch 29 → 30 not taken.
✓ Branch 29 → 31 taken 40 times.
✓ Branch 32 → 33 taken 24 times.
✓ Branch 32 → 34 taken 40 times.
|
64 | if (!current.isEmpty() || hadQuote) |
| 34 |
1/1✓ Branch 33 → 34 taken 24 times.
|
24 | tokens.append(current); |
| 35 | 64 | return tokens; | |
| 36 | 64 | } | |
| 37 | |||
| 38 | // The first arrow outside double quotes (S106-325: an address or folder in | ||
| 39 | // quotes may contain one); "→" is preferred over "->" and "=>" as before. | ||
| 40 | 38 | int arrowIndex(const QString &text, int *length) { | |
| 41 |
2/2✓ Branch 38 → 16 taken 47 times.
✓ Branch 38 → 39 taken 3 times.
|
316 | for (const QString &arrow : {QStringLiteral("→"), QStringLiteral("->"), QStringLiteral("=>")}) { |
| 42 | 47 | bool quoted = false; | |
| 43 |
2/2✓ Branch 36 → 17 taken 1261 times.
✓ Branch 36 → 37 taken 12 times.
|
1273 | for (int index = 0; index < text.size(); ++index) { |
| 44 |
2/2✓ Branch 21 → 22 taken 32 times.
✓ Branch 21 → 23 taken 1229 times.
|
1261 | if (text.at(index) == QLatin1Char('"')) |
| 45 | 32 | quoted = !quoted; | |
| 46 |
6/6✓ Branch 23 → 24 taken 1124 times.
✓ Branch 23 → 30 taken 105 times.
✓ Branch 28 → 29 taken 35 times.
✓ Branch 28 → 30 taken 1089 times.
✓ Branch 31 → 32 taken 35 times.
✓ Branch 31 → 34 taken 1194 times.
|
1229 | else if (!quoted && QStringView(text).mid(index).startsWith(arrow)) { |
| 47 | 35 | *length = int(arrow.size()); | |
| 48 | 35 | return index; | |
| 49 | } | ||
| 50 | } | ||
| 51 | 152 | } | |
| 52 | 3 | return -1; | |
| 53 | } | ||
| 54 | |||
| 55 | 43 | bool hasWildcard(const QString &value) { | |
| 56 |
5/6✓ Branch 4 → 5 taken 43 times.
✓ Branch 5 → 6 taken 42 times.
✓ Branch 5 → 10 taken 1 time.
✓ Branch 8 → 9 taken 42 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 42 times.
|
43 | return value.contains(QLatin1Char('*')) || value.contains(QLatin1Char('?')); |
| 57 | } | ||
| 58 | |||
| 59 | 43 | QVariantMap textCondition(const QString &field, const QString &value, bool negated) { | |
| 60 | 43 | QString op = QStringLiteral("contains"); | |
| 61 |
3/3✓ Branch 6 → 7 taken 43 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 15 taken 42 times.
|
43 | if (hasWildcard(value)) |
| 62 | 1 | op = QStringLiteral("matches"); | |
| 63 |
7/7✓ Branch 17 → 18 taken 16 times.
✓ Branch 17 → 21 taken 26 times.
✓ Branch 20 → 21 taken 1 time.
✓ Branch 20 → 30 taken 15 times.
✓ Branch 23 → 24 taken 27 times.
✓ Branch 24 → 25 taken 23 times.
✓ Branch 24 → 30 taken 4 times.
|
65 | else if ((field == QLatin1String("from") || field == QLatin1String("toOrCc")) && value.contains(QLatin1Char('@')) && |
| 64 |
5/5✓ Branch 27 → 28 taken 23 times.
✓ Branch 28 → 29 taken 13 times.
✓ Branch 28 → 30 taken 10 times.
✓ Branch 31 → 32 taken 13 times.
✓ Branch 31 → 39 taken 29 times.
|
65 | !value.startsWith(QLatin1Char('@'))) |
| 65 | 13 | op = QStringLiteral("is"); | |
| 66 | 129 | return {{QStringLiteral("field"), field}, {QStringLiteral("op"), op}, | |
| 67 |
4/8✓ Branch 59 → 60 taken 172 times.
✓ Branch 59 → 61 taken 43 times.
✓ Branch 65 → 66 taken 43 times.
✓ Branch 65 → 67 taken 43 times.
✗ Branch 83 → 84 not taken.
✗ Branch 83 → 85 not taken.
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 97 not taken.
|
387 | {QStringLiteral("values"), QStringList{value}}, {QStringLiteral("negated"), negated}}; |
| 68 | 258 | } | |
| 69 | |||
| 70 | 2 | bool parseSize(const QString &spec, quint64 *bytes) { | |
| 71 |
4/7✓ Branch 2 → 3 taken 1 time.
✓ Branch 2 → 15 taken 1 time.
✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 15 not taken.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 49 → 50 not taken.
✗ Branch 49 → 51 not taken.
|
3 | static const QRegularExpression pattern(QStringLiteral("^(\\d+)\\s*([kKmMgG]?)[bB]?$")); |
| 72 |
1/1✓ Branch 16 → 17 taken 2 times.
|
2 | const QRegularExpressionMatch match = pattern.match(spec); |
| 73 |
3/3✓ Branch 17 → 18 taken 2 times.
✓ Branch 18 → 19 taken 1 time.
✓ Branch 18 → 20 taken 1 time.
|
2 | if (!match.hasMatch()) |
| 74 | 1 | return false; | |
| 75 |
2/2✓ Branch 20 → 21 taken 1 time.
✓ Branch 21 → 22 taken 1 time.
|
1 | quint64 value = match.captured(1).toULongLong(); |
| 76 |
2/2✓ Branch 23 → 24 taken 1 time.
✓ Branch 24 → 25 taken 1 time.
|
1 | const QString unit = match.captured(2).toLower(); |
| 77 |
1/2✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 1 time.
|
1 | if (unit == QLatin1String("k")) |
| 78 | ✗ | value *= 1024; | |
| 79 |
1/2✓ Branch 32 → 33 taken 1 time.
✗ Branch 32 → 34 not taken.
|
1 | else if (unit == QLatin1String("m")) |
| 80 | 1 | value *= 1024 * 1024; | |
| 81 | ✗ | else if (unit == QLatin1String("g")) | |
| 82 | ✗ | value *= 1024ULL * 1024 * 1024; | |
| 83 | 1 | *bytes = value; | |
| 84 | 1 | return value > 0; | |
| 85 | 2 | } | |
| 86 | |||
| 87 | // One condition token; false with `error` set when it is not understood. | ||
| 88 | 46 | bool conditionFor(const QString &token, QVariantMap *condition, QString *error) { | |
| 89 | 46 | bool negated = false; | |
| 90 | 46 | QString word = token; | |
| 91 |
7/8✓ Branch 5 → 6 taken 46 times.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 12 taken 45 times.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✗ Branch 10 → 12 not taken.
✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 18 taken 45 times.
|
46 | if (word.startsWith(QLatin1Char('-')) && word.contains(QLatin1Char(':'))) { |
| 92 | 1 | negated = true; | |
| 93 |
1/1✓ Branch 14 → 15 taken 1 time.
|
1 | word = word.mid(1); |
| 94 | } | ||
| 95 |
1/1✓ Branch 19 → 20 taken 46 times.
|
46 | if (word.startsWith(QLatin1String("size>"), Qt::CaseInsensitive) || |
| 96 |
2/3✓ Branch 22 → 23 taken 45 times.
✓ Branch 23 → 24 taken 45 times.
✗ Branch 23 → 34 not taken.
|
45 | word.startsWith(QLatin1String("size<"), Qt::CaseInsensitive) || |
| 97 |
9/13✓ Branch 20 → 21 taken 45 times.
✓ Branch 20 → 34 taken 1 time.
✓ Branch 27 → 28 taken 45 times.
✓ Branch 28 → 29 taken 44 times.
✓ Branch 28 → 34 taken 1 time.
✓ Branch 42 → 43 taken 45 times.
✓ Branch 42 → 44 taken 1 time.
✓ Branch 44 → 45 taken 2 times.
✓ Branch 44 → 115 taken 44 times.
✗ Branch 281 → 282 not taken.
✗ Branch 281 → 283 not taken.
✗ Branch 285 → 286 not taken.
✗ Branch 285 → 287 not taken.
|
227 | word.startsWith(QStringLiteral("größe>"), Qt::CaseInsensitive) || |
| 98 |
8/13✓ Branch 32 → 33 taken 44 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 44 times.
✓ Branch 36 → 37 taken 44 times.
✓ Branch 36 → 38 taken 2 times.
✓ Branch 38 → 39 taken 44 times.
✓ Branch 38 → 40 taken 2 times.
✓ Branch 40 → 41 taken 45 times.
✓ Branch 40 → 42 taken 1 time.
✗ Branch 273 → 274 not taken.
✗ Branch 273 → 275 not taken.
✗ Branch 277 → 278 not taken.
✗ Branch 277 → 279 not taken.
|
90 | word.startsWith(QStringLiteral("größe<"), Qt::CaseInsensitive)) { |
| 99 |
2/2✓ Branch 49 → 50 taken 2 times.
✓ Branch 50 → 51 taken 2 times.
|
2 | const int at = word.indexOf(QRegularExpression(QStringLiteral("[<>]"))); |
| 100 | 2 | quint64 bytes = 0; | |
| 101 |
4/4✓ Branch 54 → 55 taken 2 times.
✓ Branch 55 → 56 taken 2 times.
✓ Branch 57 → 58 taken 1 time.
✓ Branch 57 → 62 taken 1 time.
|
2 | if (!parseSize(word.mid(at + 1), &bytes)) { |
| 102 |
1/1✓ Branch 58 → 59 taken 1 time.
|
1 | *error = QCoreApplication::translate("RuleConsoleInput", "Write sizes like size>1M or size<100K."); |
| 103 | 1 | return false; | |
| 104 | } | ||
| 105 | 3 | *condition = {{QStringLiteral("field"), QStringLiteral("size")}, | |
| 106 |
3/10✓ Branch 76 → 77 taken 1 time.
✗ Branch 76 → 80 not taken.
✗ Branch 103 → 104 not taken.
✓ Branch 103 → 105 taken 1 time.
✓ Branch 105 → 106 taken 1 time.
✗ Branch 105 → 107 not taken.
✗ Branch 323 → 324 not taken.
✗ Branch 323 → 325 not taken.
✗ Branch 327 → 328 not taken.
✗ Branch 327 → 329 not taken.
|
3 | {QStringLiteral("op"), word.at(at) == QLatin1Char('>') ? QStringLiteral("over") : QStringLiteral("under")}, |
| 107 |
2/4✓ Branch 96 → 97 taken 4 times.
✓ Branch 96 → 98 taken 1 time.
✗ Branch 306 → 307 not taken.
✗ Branch 306 → 308 not taken.
|
7 | {QStringLiteral("size"), bytes}, {QStringLiteral("negated"), negated}}; |
| 108 | 1 | return true; | |
| 109 | } | ||
| 110 | 44 | const int colon = word.indexOf(QLatin1Char(':')); | |
| 111 |
1/2✗ Branch 118 → 119 not taken.
✓ Branch 118 → 123 taken 44 times.
|
44 | if (colon <= 0) { |
| 112 | ✗ | *error = QCoreApplication::translate("RuleConsoleInput", "Start each condition with from:, to:, subject:, list:, header:, body: or size."); | |
| 113 | ✗ | return false; | |
| 114 | } | ||
| 115 |
2/2✓ Branch 123 → 124 taken 44 times.
✓ Branch 124 → 125 taken 44 times.
|
44 | const QString prefix = word.left(colon).toLower(); |
| 116 |
1/1✓ Branch 126 → 127 taken 44 times.
|
44 | const QString value = word.mid(colon + 1); |
| 117 |
1/2✗ Branch 128 → 129 not taken.
✓ Branch 128 → 133 taken 44 times.
|
44 | if (value.isEmpty()) { |
| 118 | ✗ | *error = QCoreApplication::translate("RuleConsoleInput", "A condition has no value."); | |
| 119 | ✗ | return false; | |
| 120 | } | ||
| 121 |
6/6✓ Branch 135 → 136 taken 19 times.
✓ Branch 135 → 139 taken 25 times.
✓ Branch 138 → 139 taken 1 time.
✓ Branch 138 → 140 taken 18 times.
✓ Branch 141 → 142 taken 26 times.
✓ Branch 141 → 151 taken 18 times.
|
44 | if (prefix == QLatin1String("from") || prefix == QLatin1String("von")) |
| 122 |
1/1✓ Branch 145 → 146 taken 26 times.
|
52 | *condition = textCondition(QStringLiteral("from"), value, negated); |
| 123 |
5/6✓ Branch 153 → 154 taken 17 times.
✓ Branch 153 → 157 taken 1 time.
✗ Branch 156 → 157 not taken.
✓ Branch 156 → 158 taken 17 times.
✓ Branch 159 → 160 taken 1 time.
✓ Branch 159 → 169 taken 17 times.
|
18 | else if (prefix == QLatin1String("to") || prefix == QLatin1String("an")) |
| 124 |
1/1✓ Branch 163 → 164 taken 1 time.
|
2 | *condition = textCondition(QStringLiteral("toOrCc"), value, negated); |
| 125 |
6/6✓ Branch 171 → 172 taken 4 times.
✓ Branch 171 → 175 taken 13 times.
✓ Branch 174 → 175 taken 1 time.
✓ Branch 174 → 176 taken 3 times.
✓ Branch 177 → 178 taken 14 times.
✓ Branch 177 → 187 taken 3 times.
|
17 | else if (prefix == QLatin1String("subject") || prefix == QLatin1String("betreff")) |
| 126 |
1/1✓ Branch 181 → 182 taken 14 times.
|
28 | *condition = textCondition(QStringLiteral("subject"), value, negated); |
| 127 |
5/6✓ Branch 189 → 190 taken 2 times.
✓ Branch 189 → 193 taken 1 time.
✗ Branch 192 → 193 not taken.
✓ Branch 192 → 194 taken 2 times.
✓ Branch 195 → 196 taken 1 time.
✓ Branch 195 → 205 taken 2 times.
|
3 | else if (prefix == QLatin1String("list") || prefix == QLatin1String("liste")) |
| 128 |
1/1✓ Branch 199 → 200 taken 1 time.
|
2 | *condition = textCondition(QStringLiteral("list"), value, negated); |
| 129 |
1/2✗ Branch 207 → 208 not taken.
✓ Branch 207 → 217 taken 2 times.
|
2 | else if (prefix == QLatin1String("body")) |
| 130 | ✗ | *condition = textCondition(QStringLiteral("body"), value, negated); | |
| 131 |
2/2✓ Branch 219 → 220 taken 1 time.
✓ Branch 219 → 258 taken 1 time.
|
2 | else if (prefix == QLatin1String("header")) { |
| 132 | 1 | const int equals = value.indexOf(QLatin1Char('=')); | |
| 133 |
3/6✓ Branch 223 → 224 taken 1 time.
✗ Branch 223 → 226 not taken.
✗ Branch 225 → 226 not taken.
✓ Branch 225 → 227 taken 1 time.
✗ Branch 228 → 229 not taken.
✓ Branch 228 → 233 taken 1 time.
|
1 | if (equals <= 0 || equals == value.size() - 1) { |
| 134 | ✗ | *error = QCoreApplication::translate("RuleConsoleInput", "Write header conditions like header:X-Tag=value."); | |
| 135 | ✗ | return false; | |
| 136 | } | ||
| 137 |
2/2✓ Branch 233 → 234 taken 1 time.
✓ Branch 237 → 238 taken 1 time.
|
2 | *condition = textCondition(QStringLiteral("header"), value.mid(equals + 1), negated); |
| 138 |
3/5✓ Branch 249 → 250 taken 1 time.
✓ Branch 255 → 256 taken 1 time.
✓ Branch 255 → 257 taken 1 time.
✗ Branch 423 → 424 not taken.
✗ Branch 423 → 425 not taken.
|
3 | condition->insert(QStringLiteral("headers"), QStringList{value.left(equals)}); |
| 139 | } else { | ||
| 140 |
1/1✓ Branch 258 → 259 taken 1 time.
|
1 | *error = QCoreApplication::translate("RuleConsoleInput", "Unknown condition. Use from:, to:, subject:, list:, header:, body: or size."); |
| 141 | 1 | return false; | |
| 142 | } | ||
| 143 | 43 | return true; | |
| 144 | 52 | } | |
| 145 | |||
| 146 | 33 | QVariantMap action(const QString &kind, const QString &target = {}) { | |
| 147 |
2/4✓ Branch 8 → 9 taken 33 times.
✓ Branch 8 → 10 taken 33 times.
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 49 not taken.
|
99 | QVariantMap map{{QStringLiteral("kind"), kind}}; |
| 148 |
2/2✓ Branch 13 → 14 taken 21 times.
✓ Branch 13 → 44 taken 12 times.
|
33 | if (!target.isEmpty()) |
| 149 |
7/11✓ Branch 23 → 24 taken 1 time.
✓ Branch 23 → 27 taken 20 times.
✓ Branch 30 → 31 taken 21 times.
✓ Branch 32 → 33 taken 20 times.
✓ Branch 32 → 34 taken 1 time.
✓ Branch 34 → 35 taken 1 time.
✓ Branch 34 → 36 taken 20 times.
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 66 not taken.
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 70 not taken.
|
42 | map.insert(kind == QLatin1String("label") ? QStringLiteral("flags") : QStringLiteral("target"), |
| 150 |
8/14✓ Branch 16 → 17 taken 1 time.
✓ Branch 16 → 20 taken 20 times.
✓ Branch 37 → 38 taken 1 time.
✓ Branch 37 → 39 taken 20 times.
✓ Branch 39 → 40 taken 1 time.
✓ Branch 39 → 43 taken 20 times.
✓ Branch 41 → 42 taken 1 time.
✓ Branch 41 → 43 taken 1 time.
✗ Branch 76 → 77 not taken.
✗ Branch 76 → 78 not taken.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 84 not taken.
✗ Branch 82 → 83 not taken.
✗ Branch 82 → 84 not taken.
|
44 | kind == QLatin1String("label") ? QVariant(QStringList{target}) : QVariant(target)); |
| 151 | 33 | return map; | |
| 152 | 67 | } | |
| 153 | |||
| 154 | } // namespace | ||
| 155 | |||
| 156 | 10 | QString seedFromSender(const QString &address) { | |
| 157 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 10 times.
|
10 | if (address.isEmpty()) |
| 158 | ✗ | return {}; | |
| 159 | // S106-325: a sender with an arrow or a space stays one quoted value. | ||
| 160 |
2/3✓ Branch 7 → 8 taken 10 times.
✓ Branch 8 → 9 taken 10 times.
✗ Branch 8 → 29 not taken.
|
20 | const bool quote = !address.contains(QLatin1Char('"')) && |
| 161 |
9/20✓ Branch 12 → 13 taken 10 times.
✓ Branch 13 → 14 taken 9 times.
✓ Branch 13 → 28 taken 1 time.
✓ Branch 17 → 18 taken 9 times.
✓ Branch 18 → 19 taken 9 times.
✗ Branch 18 → 28 not taken.
✓ Branch 36 → 37 taken 9 times.
✓ Branch 36 → 38 taken 1 time.
✓ Branch 38 → 39 taken 10 times.
✗ Branch 38 → 40 not taken.
✓ Branch 40 → 41 taken 10 times.
✗ Branch 40 → 42 not taken.
✗ Branch 77 → 78 not taken.
✗ Branch 77 → 79 not taken.
✗ Branch 81 → 82 not taken.
✗ Branch 81 → 83 not taken.
✗ Branch 85 → 86 not taken.
✗ Branch 85 → 87 not taken.
✗ Branch 89 → 90 not taken.
✗ Branch 89 → 91 not taken.
|
29 | (address.contains(QStringLiteral("→")) || address.contains(QStringLiteral("->")) || |
| 162 |
6/11✓ Branch 22 → 23 taken 9 times.
✓ Branch 23 → 24 taken 9 times.
✗ Branch 23 → 28 not taken.
✓ Branch 32 → 33 taken 9 times.
✓ Branch 32 → 34 taken 1 time.
✓ Branch 34 → 35 taken 9 times.
✓ Branch 34 → 36 taken 1 time.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 71 not taken.
✗ Branch 73 → 74 not taken.
✗ Branch 73 → 75 not taken.
|
19 | address.contains(QStringLiteral("=>")) || |
| 163 |
4/5✓ Branch 26 → 27 taken 9 times.
✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 9 times.
✓ Branch 30 → 31 taken 9 times.
✓ Branch 30 → 32 taken 1 time.
|
160 | std::any_of(address.cbegin(), address.cend(), [](QChar c) { return c.isSpace(); })); |
| 164 |
6/8✓ Branch 42 → 43 taken 1 time.
✓ Branch 42 → 49 taken 9 times.
✓ Branch 47 → 48 taken 1 time.
✓ Branch 48 → 50 taken 1 time.
✓ Branch 50 → 51 taken 1 time.
✓ Branch 50 → 52 taken 9 times.
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 97 not taken.
|
10 | const QString value = quote ? QLatin1Char('"') + address + QLatin1Char('"') : address; |
| 165 |
2/2✓ Branch 58 → 59 taken 10 times.
✓ Branch 59 → 60 taken 10 times.
|
20 | return QStringLiteral("from:") + value + QStringLiteral(" → "); |
| 166 | 10 | } | |
| 167 | |||
| 168 | 34 | Result parse(const QString &text, bool stopByDefault) { | |
| 169 | 34 | Result result; | |
| 170 | 34 | int arrowLength = 0; | |
| 171 |
1/1✓ Branch 2 → 3 taken 34 times.
|
34 | const int arrow = arrowIndex(text, &arrowLength); |
| 172 |
2/2✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 8 taken 32 times.
|
34 | if (arrow < 0) { |
| 173 |
1/1✓ Branch 4 → 5 taken 2 times.
|
2 | result.error = QCoreApplication::translate("RuleConsoleInput", "Add → and what should happen, e.g. → Dev/CI read."); |
| 174 | 2 | return result; | |
| 175 | } | ||
| 176 |
2/2✓ Branch 8 → 9 taken 32 times.
✓ Branch 9 → 10 taken 32 times.
|
32 | const QStringList conditionTokens = tokenize(text.left(arrow)); |
| 177 |
2/2✓ Branch 11 → 12 taken 32 times.
✓ Branch 12 → 13 taken 32 times.
|
32 | const QStringList actionTokens = tokenize(text.mid(arrow + arrowLength)); |
| 178 | 32 | QVariantList conditions; | |
| 179 | 32 | bool sawAnd = false; | |
| 180 | 32 | bool sawOr = false; | |
| 181 |
2/2✓ Branch 57 → 16 taken 49 times.
✓ Branch 57 → 58 taken 30 times.
|
79 | for (const QString &token : conditionTokens) { |
| 182 |
1/1✓ Branch 17 → 18 taken 49 times.
|
49 | const QString lower = token.toLower(); |
| 183 |
6/6✓ Branch 20 → 21 taken 48 times.
✓ Branch 20 → 24 taken 1 time.
✓ Branch 23 → 24 taken 1 time.
✓ Branch 23 → 25 taken 47 times.
✓ Branch 26 → 27 taken 2 times.
✓ Branch 26 → 28 taken 47 times.
|
49 | if (lower == QLatin1String("or") || lower == QLatin1String("oder")) { |
| 184 | 2 | sawOr = true; | |
| 185 | 2 | continue; | |
| 186 | } | ||
| 187 |
5/6✓ Branch 30 → 31 taken 46 times.
✓ Branch 30 → 34 taken 1 time.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 46 times.
✓ Branch 36 → 37 taken 1 time.
✓ Branch 36 → 38 taken 46 times.
|
47 | if (lower == QLatin1String("and") || lower == QLatin1String("und")) { |
| 188 | 1 | sawAnd = true; | |
| 189 | 1 | continue; | |
| 190 | } | ||
| 191 | 46 | QVariantMap condition; | |
| 192 |
3/3✓ Branch 38 → 39 taken 46 times.
✓ Branch 39 → 40 taken 2 times.
✓ Branch 39 → 41 taken 44 times.
|
46 | if (!conditionFor(token, &condition, &result.error)) |
| 193 | 2 | return result; | |
| 194 |
1/1✓ Branch 42 → 43 taken 44 times.
|
44 | conditions.append(condition); |
| 195 | 51 | } | |
| 196 |
4/4✓ Branch 58 → 59 taken 2 times.
✓ Branch 58 → 64 taken 28 times.
✓ Branch 59 → 60 taken 1 time.
✓ Branch 59 → 64 taken 1 time.
|
30 | if (sawOr && sawAnd) { |
| 197 |
1/1✓ Branch 60 → 61 taken 1 time.
|
1 | result.error = QCoreApplication::translate("RuleConsoleInput", "Use the editor for mixed and/or conditions."); |
| 198 | 1 | return result; | |
| 199 | } | ||
| 200 |
2/2✓ Branch 65 → 66 taken 1 time.
✓ Branch 65 → 70 taken 28 times.
|
29 | if (conditions.isEmpty()) { |
| 201 |
1/1✓ Branch 66 → 67 taken 1 time.
|
1 | result.error = QCoreApplication::translate("RuleConsoleInput", "Add at least one condition before →."); |
| 202 | 1 | return result; | |
| 203 | } | ||
| 204 | 28 | QVariantList actions; | |
| 205 | 28 | QString name; | |
| 206 | 28 | bool stop = stopByDefault; | |
| 207 |
2/2✓ Branch 297 → 72 taken 39 times.
✓ Branch 297 → 298 taken 27 times.
|
66 | for (const QString &token : actionTokens) { |
| 208 |
1/1✓ Branch 73 → 74 taken 39 times.
|
39 | const QString lower = token.toLower(); |
| 209 | 39 | const int colon = token.indexOf(QLatin1Char(':')); | |
| 210 |
3/3✓ Branch 77 → 78 taken 8 times.
✓ Branch 77 → 79 taken 31 times.
✓ Branch 78 → 80 taken 8 times.
|
39 | const QString prefix = colon > 0 ? lower.left(colon) : QString(); |
| 211 |
3/3✓ Branch 80 → 81 taken 8 times.
✓ Branch 80 → 82 taken 31 times.
✓ Branch 81 → 83 taken 8 times.
|
39 | const QString value = colon > 0 ? token.mid(colon + 1) : QString(); |
| 212 |
5/6✓ Branch 85 → 86 taken 29 times.
✓ Branch 85 → 89 taken 10 times.
✗ Branch 88 → 89 not taken.
✓ Branch 88 → 90 taken 29 times.
✓ Branch 91 → 92 taken 10 times.
✓ Branch 91 → 105 taken 29 times.
|
39 | if (lower == QLatin1String("read") || lower == QLatin1String("gelesen")) |
| 213 |
2/2✓ Branch 96 → 97 taken 10 times.
✓ Branch 98 → 99 taken 10 times.
|
20 | actions.append(action(QStringLiteral("read"))); |
| 214 |
5/6✓ Branch 107 → 108 taken 29 times.
✗ Branch 107 → 111 not taken.
✓ Branch 110 → 111 taken 1 time.
✓ Branch 110 → 112 taken 28 times.
✓ Branch 113 → 114 taken 1 time.
✓ Branch 113 → 127 taken 28 times.
|
29 | else if (lower == QLatin1String("important") || lower == QLatin1String("wichtig")) |
| 215 |
2/2✓ Branch 118 → 119 taken 1 time.
✓ Branch 120 → 121 taken 1 time.
|
2 | actions.append(action(QStringLiteral("important"))); |
| 216 |
1/2✗ Branch 129 → 130 not taken.
✓ Branch 129 → 143 taken 28 times.
|
28 | else if (lower == QLatin1String("junk")) |
| 217 | ✗ | actions.append(action(QStringLiteral("junk"))); | |
| 218 |
5/6✓ Branch 145 → 146 taken 27 times.
✓ Branch 145 → 149 taken 1 time.
✗ Branch 148 → 149 not taken.
✓ Branch 148 → 150 taken 27 times.
✓ Branch 151 → 152 taken 1 time.
✓ Branch 151 → 165 taken 27 times.
|
28 | else if (lower == QLatin1String("trash") || lower == QLatin1String("papierkorb")) |
| 219 |
2/2✓ Branch 156 → 157 taken 1 time.
✓ Branch 158 → 159 taken 1 time.
|
2 | actions.append(action(QStringLiteral("trash"))); |
| 220 |
5/6✓ Branch 167 → 168 taken 26 times.
✓ Branch 167 → 171 taken 1 time.
✗ Branch 170 → 171 not taken.
✓ Branch 170 → 172 taken 26 times.
✓ Branch 173 → 174 taken 1 time.
✓ Branch 173 → 175 taken 26 times.
|
27 | else if (lower == QLatin1String("stop") || lower == QLatin1String("stopp")) { |
| 221 | 1 | stop = true; | |
| 222 | 1 | result.explicitStop = true; | |
| 223 |
5/6✓ Branch 177 → 178 taken 23 times.
✓ Branch 177 → 181 taken 3 times.
✗ Branch 180 → 181 not taken.
✓ Branch 180 → 182 taken 23 times.
✓ Branch 183 → 184 taken 3 times.
✓ Branch 183 → 185 taken 23 times.
|
26 | } else if (lower == QLatin1String("+now") || lower == QLatin1String("+jetzt")) |
| 224 | 3 | result.applyNow = true; | |
| 225 |
5/6✓ Branch 187 → 188 taken 23 times.
✗ Branch 187 → 191 not taken.
✓ Branch 190 → 191 taken 1 time.
✓ Branch 190 → 192 taken 22 times.
✓ Branch 193 → 194 taken 1 time.
✓ Branch 193 → 205 taken 22 times.
|
23 | else if (prefix == QLatin1String("copy") || prefix == QLatin1String("kopie")) |
| 226 |
2/2✓ Branch 197 → 198 taken 1 time.
✓ Branch 199 → 200 taken 1 time.
|
1 | actions.append(action(QStringLiteral("copy"), value)); |
| 227 |
2/2✓ Branch 207 → 208 taken 1 time.
✓ Branch 207 → 235 taken 21 times.
|
22 | else if (prefix == QLatin1String("label")) { |
| 228 | 1 | bool numeric = false; | |
| 229 |
1/1✓ Branch 208 → 209 taken 1 time.
|
1 | const int number = value.toInt(&numeric); |
| 230 |
2/2✓ Branch 222 → 223 taken 1 time.
✓ Branch 224 → 225 taken 1 time.
|
1 | actions.append(action(QStringLiteral("label"), |
| 231 |
6/15✓ Branch 209 → 210 taken 1 time.
✗ Branch 209 → 218 not taken.
✓ Branch 210 → 211 taken 1 time.
✗ Branch 210 → 218 not taken.
✓ Branch 211 → 212 taken 1 time.
✗ Branch 211 → 218 not taken.
✓ Branch 216 → 217 taken 1 time.
✓ Branch 230 → 231 taken 1 time.
✗ Branch 230 → 232 not taken.
✓ Branch 232 → 233 taken 1 time.
✗ Branch 232 → 234 not taken.
✗ Branch 463 → 464 not taken.
✗ Branch 463 → 465 not taken.
✗ Branch 467 → 468 not taken.
✗ Branch 467 → 469 not taken.
|
3 | numeric && number >= 1 && number <= 5 ? QStringLiteral("$label%1").arg(number) : value)); |
| 232 |
5/6✓ Branch 237 → 238 taken 16 times.
✓ Branch 237 → 241 taken 5 times.
✗ Branch 240 → 241 not taken.
✓ Branch 240 → 242 taken 16 times.
✓ Branch 243 → 244 taken 5 times.
✓ Branch 243 → 258 taken 16 times.
|
21 | } else if (prefix == QLatin1String("forward") || prefix == QLatin1String("weiter")) { |
| 233 |
2/2✓ Branch 247 → 248 taken 5 times.
✓ Branch 249 → 250 taken 5 times.
|
5 | actions.append(action(QStringLiteral("forwardCopy"), value)); |
| 234 |
2/2✓ Branch 254 → 255 taken 5 times.
✓ Branch 255 → 256 taken 5 times.
|
5 | result.forwardTargets.append(value.toLower()); |
| 235 |
2/2✓ Branch 260 → 261 taken 1 time.
✓ Branch 260 → 262 taken 15 times.
|
16 | } else if (prefix == QLatin1String("name")) |
| 236 | 1 | name = value; | |
| 237 |
1/2✓ Branch 263 → 264 taken 15 times.
✗ Branch 263 → 282 not taken.
|
15 | else if (!token.isEmpty()) { |
| 238 |
2/2✓ Branch 265 → 266 taken 1 time.
✓ Branch 265 → 270 taken 14 times.
|
15 | if (!result.folder.isEmpty()) { |
| 239 |
1/1✓ Branch 266 → 267 taken 1 time.
|
1 | result.error = QCoreApplication::translate("RuleConsoleInput", "Only one target folder per rule; use copy:Folder for more."); |
| 240 | 1 | return result; | |
| 241 | } | ||
| 242 | 14 | result.folder = token; | |
| 243 |
2/2✓ Branch 274 → 275 taken 14 times.
✓ Branch 276 → 277 taken 14 times.
|
14 | actions.prepend(action(QStringLiteral("move"), token)); |
| 244 | } | ||
| 245 | 41 | } | |
| 246 |
2/2✓ Branch 299 → 300 taken 8 times.
✓ Branch 299 → 304 taken 19 times.
|
27 | if (actions.isEmpty()) { |
| 247 |
1/1✓ Branch 300 → 301 taken 8 times.
|
8 | result.error = QCoreApplication::translate("RuleConsoleInput", "Add what should happen after →, e.g. a folder or read."); |
| 248 | 8 | return result; | |
| 249 | } | ||
| 250 | 38 | result.draft = {{QStringLiteral("name"), name}, | |
| 251 | 38 | {QStringLiteral("enabled"), true}, | |
| 252 | 38 | {QStringLiteral("matchAll"), !sawOr}, | |
| 253 | 38 | {QStringLiteral("stop"), stop}, | |
| 254 | 38 | {QStringLiteral("blockIndex"), -1}, | |
| 255 | 38 | {QStringLiteral("conditions"), conditions}, | |
| 256 |
2/4✓ Branch 336 → 337 taken 133 times.
✓ Branch 336 → 338 taken 19 times.
✗ Branch 513 → 514 not taken.
✗ Branch 513 → 515 not taken.
|
171 | {QStringLiteral("actions"), actions}}; |
| 257 | 19 | result.ok = true; | |
| 258 | 19 | return result; | |
| 259 | 203 | } | |
| 260 | |||
| 261 | 4 | QString completeFolder(const QString &text, const QStringList &folders) { | |
| 262 | 4 | int arrowLength = 0; | |
| 263 |
1/1✓ Branch 2 → 3 taken 4 times.
|
4 | const int arrow = arrowIndex(text, &arrowLength); |
| 264 |
2/2✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 3 times.
|
4 | if (arrow < 0) |
| 265 | 1 | return {}; | |
| 266 | 3 | const int start = text.lastIndexOf(QLatin1Char(' ')) + 1; | |
| 267 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 3 times.
|
3 | if (start <= arrow) |
| 268 | ✗ | return {}; | |
| 269 |
1/1✓ Branch 10 → 11 taken 3 times.
|
3 | const QString partial = text.mid(start); |
| 270 | 3 | QString prefix; | |
| 271 | 3 | QString stem = partial; | |
| 272 | 3 | const int colon = partial.indexOf(QLatin1Char(':')); | |
| 273 |
2/2✓ Branch 15 → 16 taken 1 time.
✓ Branch 15 → 23 taken 2 times.
|
3 | if (colon > 0) { |
| 274 |
1/1✓ Branch 16 → 17 taken 1 time.
|
1 | prefix = partial.left(colon + 1); |
| 275 |
1/1✓ Branch 19 → 20 taken 1 time.
|
1 | stem = partial.mid(colon + 1); |
| 276 | } | ||
| 277 |
8/18✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 34 taken 2 times.
✓ Branch 26 → 27 taken 1 time.
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 34 taken 1 time.
✗ Branch 30 → 31 not taken.
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 3 times.
✓ Branch 37 → 38 taken 1 time.
✓ Branch 37 → 39 taken 2 times.
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 3 times.
✗ Branch 83 → 84 not taken.
✗ Branch 83 → 85 not taken.
✗ Branch 88 → 89 not taken.
✗ Branch 88 → 90 not taken.
|
3 | if (!prefix.isEmpty() && prefix.toLower() != QLatin1String("copy:") && prefix.toLower() != QLatin1String("kopie:")) |
| 278 | ✗ | return {}; | |
| 279 |
1/2✓ Branch 74 → 43 taken 10 times.
✗ Branch 74 → 75 not taken.
|
10 | for (const QString &folder : folders) |
| 280 |
6/7✓ Branch 44 → 45 taken 10 times.
✓ Branch 45 → 46 taken 3 times.
✓ Branch 45 → 49 taken 7 times.
✓ Branch 47 → 48 taken 3 times.
✗ Branch 47 → 49 not taken.
✓ Branch 50 → 51 taken 3 times.
✓ Branch 50 → 72 taken 7 times.
|
10 | if (folder.startsWith(stem, Qt::CaseInsensitive) && folder.compare(stem, Qt::CaseInsensitive) != 0) { |
| 281 |
7/9✓ Branch 53 → 54 taken 3 times.
✓ Branch 54 → 55 taken 1 time.
✓ Branch 54 → 61 taken 2 times.
✓ Branch 59 → 60 taken 1 time.
✓ Branch 60 → 62 taken 1 time.
✓ Branch 62 → 63 taken 1 time.
✓ Branch 62 → 64 taken 2 times.
✗ Branch 93 → 94 not taken.
✗ Branch 93 → 95 not taken.
|
3 | const QString value = folder.contains(QLatin1Char(' ')) ? QLatin1Char('"') + folder + QLatin1Char('"') : folder; |
| 282 |
3/3✓ Branch 64 → 65 taken 3 times.
✓ Branch 65 → 66 taken 3 times.
✓ Branch 66 → 67 taken 3 times.
|
3 | return text.left(start) + prefix + value; |
| 283 | 3 | } | |
| 284 | ✗ | return {}; | |
| 285 | 3 | } | |
| 286 | |||
| 287 | } // namespace RuleConsoleInput | ||
| 288 |