aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_mainwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_mainwindow.cpp')
-rw-r--r--tests/test_mainwindow.cpp197
1 files changed, 197 insertions, 0 deletions
diff --git a/tests/test_mainwindow.cpp b/tests/test_mainwindow.cpp
index faa8481..818e5b4 100644
--- a/tests/test_mainwindow.cpp
+++ b/tests/test_mainwindow.cpp
@@ -173,6 +173,10 @@ private slots:
void thereIsNoSentButtonWithoutASentKey();
void theSentButtonRunsEveryConfiguredAccount();
void theSentButtonSurvivesABracketedPath();
+ void placeholderCountsSkipSentAndDraftsWithoutTheKeys();
+ void placeholderCountsCarrySentAndDrafts();
+ void placeholderLabelsStayPairedWithTheirQueries();
+ void placeholderCountsDropAnUncountableQuery();
void flatModeDoesNotSurviveTheNextQuery();
void noTwoActionsShareAnIcon();
};
@@ -4639,6 +4643,199 @@ void TestMainWindow::theSentButtonSurvivesABracketedPath()
QStringLiteral("path:\"provider-a/[Provider]/Posta inviata/**\""));
}
+namespace {
+
+/// Writes a config whose accounts carry a sent folder, a drafts folder, or
+/// neither. Separate from writeSentConfig() because the two keys are
+/// independent: the interesting cases here are exactly the ones where an
+/// account has one and not the other.
+struct FolderAccount {
+ QString maildir;
+ QString sent;
+ QString drafts;
+};
+
+QString writeFolderConfig(const QTemporaryDir &dir,
+ const QList<FolderAccount> &accounts)
+{
+ const QString path = dir.filePath(QStringLiteral("qtmaildir.conf"));
+ QSettings s(path, QSettings::IniFormat);
+ for (const FolderAccount &account : accounts) {
+ s.beginGroup(QStringLiteral("account.") + account.maildir);
+ s.setValue(QStringLiteral("maildir"), account.maildir);
+ if (!account.sent.isEmpty())
+ s.setValue(QStringLiteral("sent"), account.sent);
+ if (!account.drafts.isEmpty())
+ s.setValue(QStringLiteral("drafts"), account.drafts);
+ s.endGroup();
+ }
+ s.sync();
+ return path;
+}
+
+/// The label of the helper whose query is `query`, or a null string.
+QString labelForQuery(const QList<HtmlBuilder::PlaceholderHelper> &helpers,
+ const QString &query)
+{
+ for (const HtmlBuilder::PlaceholderHelper &helper : helpers) {
+ if (helper.query == query)
+ return helper.label;
+ }
+ return QString();
+}
+
+} // namespace
+
+void TestMainWindow::placeholderCountsSkipSentAndDraftsWithoutTheKeys()
+{
+ // The tag: lines are unconditional, the folder lines are not. An account
+ // with no sent or drafts folder must contribute no line at all rather than
+ // a line reading 0: item 63 established that a missing folder is a real
+ // configuration, and "0 sent" claims the user has sent nothing.
+ QTemporaryDir dir;
+ QVERIFY(dir.isValid());
+ Config config;
+ config.load(writeFolderConfig(dir, {{QStringLiteral("provider-c"), {}, {}}}));
+
+ MainWindow window(config);
+
+ const QStringList queries = window.placeholderQueriesForTesting();
+ QCOMPARE(queries.size(), 3);
+ QVERIFY(queries.contains(QStringLiteral("tag:unread")));
+ QVERIFY(queries.contains(QStringLiteral("tag:flagged")));
+ QVERIFY(queries.contains(QStringLiteral("tag:inbox")));
+}
+
+void TestMainWindow::placeholderCountsCarrySentAndDrafts()
+{
+ // Both composed from the folder keys rather than from a tag. `tag:draft`
+ // counts 0 against the user's real database (measured 2026-08-11) and no
+ // draft-ish tag exists in it at all, so a tag-based drafts line would be a
+ // permanent zero that looks like working code.
+ //
+ // The account layout is the real one's shape: one account with both keys,
+ // one with drafts and NO sent, which is what proves the two are collected
+ // independently rather than per-account in one pass.
+ QTemporaryDir dir;
+ QVERIFY(dir.isValid());
+ Config config;
+ config.load(writeFolderConfig(dir, {
+ {QStringLiteral("webmail-primary"), QStringLiteral("Sent"),
+ QStringLiteral("Drafts")},
+ {QStringLiteral("provider-a"), {}, QStringLiteral("[Provider]/Bozze")},
+ }));
+
+ MainWindow window(config);
+
+ const QStringList queries = window.placeholderQueriesForTesting();
+ QCOMPARE(queries.size(), 5);
+
+ // The quoting survives the trip, which is the trap this whole composition
+ // exists for: unquoted, "[" and "]" are Xapian syntax and the count reads
+ // 0 while looking like an empty folder.
+ QVERIFY2(queries.contains(config.allDraftsQuery()),
+ qPrintable(QStringLiteral("drafts query missing, got: %1")
+ .arg(queries.join(QStringLiteral(" | ")))));
+ QVERIFY(queries.contains(config.allSentQuery()));
+ QVERIFY(config.allDraftsQuery().contains(
+ QStringLiteral("path:\"provider-a/[Provider]/Bozze/**\"")));
+
+ // The sent term comes from the account that has one, and the drafts terms
+ // from both. An implementation that emitted a folder line per account
+ // would produce four folder queries instead of two.
+ QCOMPARE(config.allSentQuery().count(QStringLiteral("path:")), 1);
+ QCOMPARE(config.allDraftsQuery().count(QStringLiteral("path:")), 2);
+}
+
+void TestMainWindow::placeholderLabelsStayPairedWithTheirQueries()
+{
+ // The defect this guards is the one the old fixed array invited: the
+ // labels were written positionally against a separate query array, so
+ // inserting an entry in one and not the other put a real number against
+ // the wrong name. Asserting the PAIRING rather than the order is what
+ // survives a later reshuffle.
+ QTemporaryDir dir;
+ QVERIFY(dir.isValid());
+ Config config;
+ config.load(writeFolderConfig(dir, {
+ {QStringLiteral("webmail-primary"), QStringLiteral("Sent"),
+ QStringLiteral("Drafts")},
+ }));
+
+ MainWindow window(config);
+
+ const QStringList queries = window.placeholderQueriesForTesting();
+ QCOMPARE(queries.size(), 5);
+
+ // Distinct counts, so a label reading the wrong index cannot coincide with
+ // the right answer. Positional against the queries the window just asked
+ // for, which is exactly the contract requestCounts() replies under.
+ QVector<int> counts;
+ for (int i = 0; i < queries.size(); ++i)
+ counts.append((i + 1) * 10);
+
+ QMetaObject::invokeMethod(&window, "onCountsReady",
+ Q_ARG(QVector<int>, counts),
+ Q_ARG(quint64, window.countsGenerationForTesting()));
+
+ const QList<HtmlBuilder::PlaceholderHelper> helpers =
+ window.placeholderHelpersForTesting();
+
+ for (int i = 0; i < queries.size(); ++i) {
+ const QString label = labelForQuery(helpers, queries.at(i));
+ QVERIFY2(!label.isNull(),
+ qPrintable(QStringLiteral("no helper for query '%1'")
+ .arg(queries.at(i))));
+ QVERIFY2(label.contains(QString::number(counts.at(i))),
+ qPrintable(QStringLiteral("query '%1' was labelled '%2', which "
+ "does not carry its own count %3")
+ .arg(queries.at(i), label)
+ .arg(counts.at(i))));
+ }
+
+ // And the folder lines say what they are, not "in inbox".
+ QVERIFY(labelForQuery(helpers, config.allSentQuery())
+ .contains(QStringLiteral("sent")));
+ QVERIFY(labelForQuery(helpers, config.allDraftsQuery())
+ .contains(QStringLiteral("draft")));
+}
+
+void TestMainWindow::placeholderCountsDropAnUncountableQuery()
+{
+ // The worker answers -1 for a query it could not count, rather than
+ // skipping the entry, precisely so the positional pairing holds. The pane
+ // must then drop that LINE rather than print a negative number, and drop
+ // only that one.
+ QTemporaryDir dir;
+ QVERIFY(dir.isValid());
+ Config config;
+ config.load(writeFolderConfig(dir, {
+ {QStringLiteral("webmail-primary"), QStringLiteral("Sent"),
+ QStringLiteral("Drafts")},
+ }));
+
+ MainWindow window(config);
+
+ const QStringList queries = window.placeholderQueriesForTesting();
+ QVector<int> counts;
+ for (int i = 0; i < queries.size(); ++i)
+ counts.append(i == 0 ? -1 : (i + 1) * 10);
+
+ QMetaObject::invokeMethod(&window, "onCountsReady",
+ Q_ARG(QVector<int>, counts),
+ Q_ARG(quint64, window.countsGenerationForTesting()));
+
+ const QList<HtmlBuilder::PlaceholderHelper> helpers =
+ window.placeholderHelpersForTesting();
+
+ QVERIFY(labelForQuery(helpers, queries.at(0)).isNull());
+ for (int i = 1; i < queries.size(); ++i) {
+ QVERIFY2(!labelForQuery(helpers, queries.at(i)).isNull(),
+ qPrintable(QStringLiteral("an uncountable query took '%1' "
+ "down with it").arg(queries.at(i))));
+ }
+}
+
void TestMainWindow::flatModeDoesNotSurviveTheNextQuery()
{
// The condition the user set for this feature: a flat Sent list is fine, a