aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-12 11:49:40 +0200
committerDanilo M. <danix@danix.xyz>2026-08-12 11:49:40 +0200
commit01ecb8c4e3bbf8176ca9d4085734ed2ec0774c80 (patch)
treeb0051bd24959fd544bf55d099ca91fc51cdd3950 /tests
parentd14c0224826f821b34c894037ab668ddfde29a6d (diff)
downloadqtmaildir-01ecb8c4e3bbf8176ca9d4085734ed2ec0774c80.tar.gz
qtmaildir-01ecb8c4e3bbf8176ca9d4085734ed2ec0774c80.zip
feat(worker): count messages as well as threads
requestCounts counts threads, which is right for the placeholder pane. A tagging rule tags messages, so a dry run over rules needs the message count or it understates every rule that matches part of a thread.
Diffstat (limited to 'tests')
-rw-r--r--tests/test_notmuchworker.cpp61
1 files changed, 61 insertions, 0 deletions
diff --git a/tests/test_notmuchworker.cpp b/tests/test_notmuchworker.cpp
index fe0247c..1db26c7 100644
--- a/tests/test_notmuchworker.cpp
+++ b/tests/test_notmuchworker.cpp
@@ -77,6 +77,9 @@ private slots:
void requestDatabaseStatsCountsMessagesNotThreads();
void requestDatabaseStatsOnUnreadableConfigEmitsError();
+ void messageCountsCountMessagesNotThreads();
+ void messageCountsReportAnInvalidQueryAsMinusOne();
+
private:
/// Tags of one message, read back through a fresh worker query.
QStringList tagsOf(const QString &messageId);
@@ -797,6 +800,64 @@ void TestNotmuchWorker::requestCountsKeepsPositionOnAnInvalidQuery()
QCOMPARE(counts.at(2), 5);
}
+void TestNotmuchWorker::messageCountsCountMessagesNotThreads()
+{
+ // The fixture is 6 messages in 5 threads: thread A carries a reply, every
+ // other thread is a single message. That difference is the whole reason
+ // this slot exists beside requestCounts, and it is what the numbers below
+ // assert. A rule that matched one reply of a 30-message thread would be
+ // reported as 1 by a thread count, understating it by 29.
+ NotmuchWorker worker(m_fixture.configPath());
+
+ QSignalSpy messages(&worker, &NotmuchWorker::messageCountsReady);
+ QSignalSpy threads(&worker, &NotmuchWorker::countsReady);
+
+ worker.requestMessageCounts({ QStringLiteral("*") }, 1);
+ worker.requestCounts({ QStringLiteral("*") }, 1);
+
+ QCOMPARE(messages.count(), 1);
+ QCOMPARE(threads.count(), 1);
+
+ const QVector<int> messageCounts =
+ messages.first().at(0).value<QVector<int>>();
+ const QVector<int> threadCounts =
+ threads.first().at(0).value<QVector<int>>();
+
+ QCOMPARE(messageCounts, (QVector<int>{ 6 }));
+ // The guard that makes this test mean something: if requestMessageCounts
+ // were implemented with count_threads it would return 5 here and match
+ // the thread count, and the assertion above would be the only thing that
+ // caught it.
+ QCOMPARE(threadCounts, (QVector<int>{ 5 }));
+}
+
+void TestNotmuchWorker::messageCountsReportAnInvalidQueryAsMinusOne()
+{
+ // Paired positionally with the caller's rules, so a dropped answer would
+ // put a real number against the wrong rule.
+ //
+ // **notmuch's query parser rejects almost nothing**, exactly as
+ // requestCountsKeepsPositionOnAnInvalidQuery records for the thread count:
+ // `from:((((` parses and matches nothing rather than failing, measured at
+ // 0 against a throwaway database rather than assumed. So this asserts the
+ // positional contract, which is the property a dry run depends on, and not
+ // a -1 that no query string can provoke. The -1 branch remains for a
+ // notmuch_query_create allocation failure, which a test cannot reach.
+ NotmuchWorker worker(m_fixture.configPath());
+
+ QSignalSpy spy(&worker, &NotmuchWorker::messageCountsReady);
+ worker.requestMessageCounts({ QStringLiteral("from:(((("),
+ QStringLiteral("*") }, 1);
+
+ QCOMPARE(spy.count(), 1);
+ const QVector<int> counts = spy.first().at(0).value<QVector<int>>();
+ QCOMPARE(counts.size(), 2);
+ QCOMPARE(counts.at(0), 0);
+ // The query beside it keeps its own answer at its own position, which is
+ // what pairs a count with the rule that produced it.
+ QCOMPARE(counts.at(1), 6);
+}
+
void TestNotmuchWorker::requestDatabaseStatsCountsMessagesNotThreads()
{
NotmuchWorker worker(m_fixture.configPath());