aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-14 11:26:39 +0200
committerDanilo M. <danix@danix.xyz>2026-08-14 11:26:39 +0200
commit80d78727bf9a73f609e6456fd114951b6daf347b (patch)
treefd050f9f3aa5945e062d098390b7ebddf6354e66 /tests
parent5694cf6feadd51a047455ae28a02d25d55f83987 (diff)
downloadqtmaildir-80d78727bf9a73f609e6456fd114951b6daf347b.tar.gz
qtmaildir-80d78727bf9a73f609e6456fd114951b6daf347b.zip
test(rules): pin a seeded id against colliding with a rule
The name comes from queries.json, so nothing had ever checked it against the ids in rules.json. Replacing the matched rule would retag mail against a query the user never associated with it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/test_tagrules.cpp40
1 files changed, 40 insertions, 0 deletions
diff --git a/tests/test_tagrules.cpp b/tests/test_tagrules.cpp
index 37dcc19..3954d80 100644
--- a/tests/test_tagrules.cpp
+++ b/tests/test_tagrules.cpp
@@ -46,6 +46,7 @@ private slots:
void theWarningReadsAsAWarningAndSitsBesideSave();
void aDismissedWarningComesBackWhenThereIsSomethingNewToSay();
void aSeededDialogOpensOnTheNewRuleWithoutWritingIt();
+ void aSeededIdThatCollidesDoesNotReplaceTheRuleItMatches();
void aNameTypedWithSpacesIsSanitisedInTheField();
void aRuleAddedAndNamedInTheDialogSurvivesAReopen();
void unknownFieldsSurviveASave();
@@ -971,6 +972,45 @@ void TestTagRules::aSeededDialogOpensOnTheNewRuleWithoutWritingIt()
QCOMPARE(onDisk.rules().size(), 1);
}
+void TestTagRules::aSeededIdThatCollidesDoesNotReplaceTheRuleItMatches()
+{
+ // A saved query named "Vendor" sanitises to "vendor", which is already a
+ // rule id here. Replacing that rule would silently retag mail against a
+ // query the user never associated with it.
+ QTemporaryDir configHome;
+ QVERIFY(configHome.isValid());
+ qputenv("XDG_CONFIG_HOME", configHome.path().toUtf8());
+ QVERIFY(QDir().mkpath(configHome.filePath(QStringLiteral("mailrules"))));
+
+ const QString stored = configHome.filePath(
+ QStringLiteral("mailrules/rules.json"));
+ QFile out(stored);
+ QVERIFY(out.open(QIODevice::WriteOnly));
+ out.write(R"({
+ "version": 1,
+ "rules": [
+ {"id": "vendor", "query": "from:vendor.example.org",
+ "add": ["vendor"], "stage": 50, "enabled": true}
+ ]
+ })");
+ out.close();
+
+ TagRule seed;
+ seed.id = TagRules::sanitiseId(QStringLiteral("Vendor"));
+ seed.query = QStringLiteral("from:other.example.org");
+
+ TagRulesDialog dialog(seed);
+
+ QCOMPARE(dialog.ruleCountForTest(), 2);
+ QCOMPARE(dialog.nameLineForTest(), QStringLiteral("vendor-2"));
+
+ // And the rule it collided with is untouched.
+ dialog.selectRuleForTest(0);
+ QCOMPARE(dialog.nameLineForTest(), QStringLiteral("vendor"));
+ QCOMPARE(dialog.queryLineForTest(),
+ QStringLiteral("from:vendor.example.org"));
+}
+
void TestTagRules::aFolderRowUsesTheDropdownAndKeepsItsSuffix()
{
// A path: without its suffix matches nothing and notmuch says nothing