diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-13 17:00:55 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-13 17:00:55 +0200 |
| commit | b8de7ce746718c7193e40b0f70cd3e2178f4ed8a (patch) | |
| tree | ab280755094321666d29d50694c48722809d953c /tests | |
| parent | 1ab12862fd47bf3816f7fad7b8a96eceb8f84272 (diff) | |
| download | qtmaildir-b8de7ce746718c7193e40b0f70cd3e2178f4ed8a.tar.gz qtmaildir-b8de7ce746718c7193e40b0f70cd3e2178f4ed8a.zip | |
feat(rules): preview a rule's mail in the thread list
Item 77. The dialog could say how many messages a rule matched and not
which ones. A Preview in list button now runs the selected rule's query
in the main window; the dialog stays open, since comparing the rule
against its results is the point.
Two constraints from the backlog entry, both now asserted and both
mutation-checked.
The query runs exactly as stored, with no tag:new and no wrapping
parentheses. The post-new hook adds those when it applies a rule, and a
preview that copied them would match nothing outside a sync window,
since tag:new is set only on mail that has just arrived.
The account selector is cleared first. runQuery() wraps the bar's text
in the selected account's scope, and a rule query usually names its own
path already, so previewing one with an account selected would scope it
twice and show an empty list, which reads as "this rule collects no
mail".
The second mutation only fails once the test's config has an account to
select: with the default empty config the selector sits on "All
accounts" anyway, and asserting that a preview leaves it there passed
against the mutation. Recorded in the test.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_tagrules.cpp | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/tests/test_tagrules.cpp b/tests/test_tagrules.cpp index 268c41f..ed3a06d 100644 --- a/tests/test_tagrules.cpp +++ b/tests/test_tagrules.cpp @@ -20,6 +20,7 @@ #include <QTemporaryDir> #include <QtTest> +#include "config.h" #include "mainwindow.h" #include "rulequery.h" #include "tagrules.h" @@ -55,6 +56,8 @@ private slots: void theWindowSizeIsSavedOnEveryWayOutOfTheDialog(); void aReloadDoesNotDiscardARestoredColumnWidth(); void manyConditionRowsDoNotSqueezeTheRuleList(); + void previewEmitsTheRuleQueryAsStored(); + void previewClearsTheAccountScope(); private: QString writeRules(const QString &json); @@ -867,5 +870,76 @@ void TestTagRules::manyConditionRowsDoNotSqueezeTheRuleList() .arg(dialog.conditionAreaHeightForTest()))); } +void TestTagRules::previewEmitsTheRuleQueryAsStored() +{ + // The query goes out EXACTLY as stored: no tag:new, no wrapping + // parentheses. The hook adds both when it applies a rule, and a preview + // that copied it would show nothing at all outside a sync window, since + // tag:new is only set on mail that has just arrived. + QTemporaryDir configHome; + QVERIFY(configHome.isValid()); + qputenv("XDG_CONFIG_HOME", configHome.path().toUtf8()); + QVERIFY(QDir().mkpath(configHome.filePath(QStringLiteral("mailrules")))); + + QFile out(configHome.filePath(QStringLiteral("mailrules/rules.json"))); + QVERIFY(out.open(QIODevice::WriteOnly)); + out.write(R"({ + "version": 1, + "rules": [ + {"id": "promo", "query": "from:a.example.org or from:b.example.org", + "add": ["promo"], "stage": 50, "enabled": true} + ] + })"); + out.close(); + + TagRulesDialog dialog; + QSignalSpy spy(&dialog, &TagRulesDialog::previewRequested); + + dialog.selectRuleForTest(0); + dialog.previewForTest(); + + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.first().at(0).toString(), + QStringLiteral("from:a.example.org or from:b.example.org")); +} + +void TestTagRules::previewClearsTheAccountScope() +{ + // runQuery() wraps the bar's text in the selected account's scope. A rule + // query usually names its own path already (path:"work/**"), so previewing + // one while an account is selected would scope it twice and show nothing, + // which reads as "the rule matches no mail" rather than as a UI fault. + QTemporaryDir configHome; + QVERIFY(configHome.isValid()); + qputenv("XDG_CONFIG_HOME", configHome.path().toUtf8()); + + // An account that can actually BE selected. With the default empty config + // the selector holds only "All accounts", so it sits at index 0 already + // and the assertion below passes whether or not the preview clears it: + // measured, the mutation removing the reset survived until this config + // was added. + const QString confPath = configHome.filePath(QStringLiteral("q.conf")); + QFile conf(confPath); + QVERIFY(conf.open(QIODevice::WriteOnly | QIODevice::Text)); + conf.write("[account.work]\nmaildir=work-mail\n"); + conf.close(); + + Config config; + config.load(confPath); + QCOMPARE(config.accounts().size(), 1); + + MainWindow window(config); + window.selectAccountForTesting(QStringLiteral("work")); + QCOMPARE(window.selectedAccountForTesting(), QStringLiteral("work")); + + window.previewRuleQueryForTesting(QStringLiteral("from:a.example.org")); + + QCOMPARE(window.queryTextForTesting(), + QStringLiteral("from:a.example.org")); + QVERIFY2(window.selectedAccountForTesting().isEmpty(), + "a preview must run unscoped, or an account-scoped rule query " + "is wrapped twice and matches nothing"); +} + QTEST_MAIN(TestTagRules) #include "test_tagrules.moc" |
