summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-17 19:58:51 +0200
committerDanilo M. <danix@danix.xyz>2026-08-17 19:58:51 +0200
commitd5e9ec157946635294001b57ce8353a109ec5051 (patch)
tree74a2f72973d1535d684b76cb24d4bc3118bb35a3 /tests
parent9899b9af523ad2aef55300c9132d21a687a0a19d (diff)
downloadqtmaildir-d5e9ec157946635294001b57ce8353a109ec5051.tar.gz
qtmaildir-d5e9ec157946635294001b57ce8353a109ec5051.zip
feat(config): add the trash query generator
Adds trash as a fifth built-in query filter beside Unread, Inbox, Important and Sent, composing per-account exactly as Sent does: Config::resolvedQuery() asks each account for its own trashQuery() rather than wrapping the all-accounts union, and an account with no trash folder resolves to matchNothingQuery() rather than "match everything". Also gives the Trash button a toolbar icon (user-trash) and a trash key to the mainwindow fixture that asserts every filter button carries one; without it the button is skipped from the row entirely (no account configured a trash folder), and the existing icon test found no button to check.
Diffstat (limited to 'tests')
-rw-r--r--tests/test_config.cpp55
-rw-r--r--tests/test_mainwindow.cpp16
2 files changed, 66 insertions, 5 deletions
diff --git a/tests/test_config.cpp b/tests/test_config.cpp
index 10dcf68..ea5c363 100644
--- a/tests/test_config.cpp
+++ b/tests/test_config.cpp
@@ -119,6 +119,8 @@ private slots:
void anAccountCarriesItsTrashFolder();
void aBracketedTrashFolderIsQuoted();
void anAccountWithoutATrashFolderWarns();
+ void theTrashFilterComposesPerAccount();
+ void theTrashFilterMatchesNothingWithoutAFolder();
};
static QString writeIni(const QTemporaryDir &dir, const QString &body)
@@ -1009,6 +1011,54 @@ void TestConfig::anAccountWithoutATrashFolderWarns()
QVERIFY(joined.contains(QStringLiteral("trash")));
}
+void TestConfig::theTrashFilterComposesPerAccount()
+{
+ // Two accounts, one with a plain folder and one nested under a bracketed
+ // parent, since the real setup has both shapes.
+ QTemporaryDir dir;
+ Config config;
+ config.load(writeIni(dir, QStringLiteral(
+ "[account.work]\n"
+ "maildir=work\n"
+ "trash=Trash\n"
+ "\n"
+ "[account.personal]\n"
+ "maildir=personal\n"
+ "trash=[Provider]/Cestino\n")));
+
+ const SavedQuery trash = Config::builtinFilter(QStringLiteral("trash"));
+ QVERIFY(trash.isGenerated());
+
+ // All accounts: the union, never a bare path that would match one account.
+ const QString all = config.resolvedQuery(trash, QString());
+ QVERIFY(all.contains(QStringLiteral("path:\"work/Trash/**\"")));
+ QVERIFY(all.contains(
+ QStringLiteral("path:\"personal/[Provider]/Cestino/**\"")));
+
+ // One account: that account's OWN query. Asserting on the STRING, not on a
+ // row count: the all-accounts query wrapped in this account's path returns
+ // exactly the right rows, because path: is hierarchical, so a count passes
+ // against the wrong thing. Config::resolvedQuery documents this trap.
+ const QString scoped = config.resolvedQuery(trash, QStringLiteral("work"));
+ QCOMPARE(scoped, QStringLiteral("path:\"work/Trash/**\""));
+ QVERIFY(!scoped.contains(QStringLiteral("personal")));
+}
+
+void TestConfig::theTrashFilterMatchesNothingWithoutAFolder()
+{
+ // An empty query means "match everything" to notmuch, so a filter with
+ // nothing to match must say so explicitly. A button labelled Trash that
+ // showed the whole Maildir is the failure this prevents.
+ QTemporaryDir dir;
+ Config config;
+ config.load(writeIni(dir, QStringLiteral(
+ "[account.work]\n"
+ "maildir=work\n")));
+
+ const SavedQuery trash = Config::builtinFilter(QStringLiteral("trash"));
+ QCOMPARE(config.resolvedQuery(trash, QString()), Config::matchNothingQuery());
+}
+
void TestConfig::sentQueryComposesWithScopedQuery()
{
// A Sent view under one account must not show another account's sent mail.
@@ -1432,7 +1482,7 @@ void TestConfig::everyBuiltinFilterIsAKnownGenerator()
Config config;
const QList<SavedQuery> filters = config.builtinFilters();
- QCOMPARE(filters.size(), 4);
+ QCOMPARE(filters.size(), 5);
QStringList names;
for (const SavedQuery &filter : filters) {
@@ -1453,7 +1503,8 @@ void TestConfig::everyBuiltinFilterIsAKnownGenerator()
QCOMPARE(names, (QStringList{ QStringLiteral("Unread"),
QStringLiteral("Inbox"),
QStringLiteral("Important"),
- QStringLiteral("Sent") }));
+ QStringLiteral("Sent"),
+ QStringLiteral("Trash") }));
}
void TestConfig::aFilterAcrossAllAccountsIsTheUnscopedQuery()
diff --git a/tests/test_mainwindow.cpp b/tests/test_mainwindow.cpp
index b188ef4..7316689 100644
--- a/tests/test_mainwindow.cpp
+++ b/tests/test_mainwindow.cpp
@@ -7922,10 +7922,20 @@ void TestMainWindow::everyBuiltinFilterButtonCarriesAnIconAndItsText()
// which is the same argument the Save button records.
QTemporaryDir dir;
QVERIFY(dir.isValid());
- Config config;
- config.load(writeSentConfig(dir, {
+ const QString path = writeSentConfig(dir, {
{QStringLiteral("work"), QStringLiteral("Sent")},
- }));
+ });
+ // A trash key too, or the Trash filter finds nothing and is skipped from
+ // the row entirely (item 103), leaving no trashButton for this loop to
+ // find.
+ {
+ QSettings s(path, QSettings::IniFormat);
+ s.beginGroup(QStringLiteral("account.work"));
+ s.setValue(QStringLiteral("trash"), QStringLiteral("Trash"));
+ s.endGroup();
+ }
+ Config config;
+ config.load(path);
MainWindow window(config);