diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-06 16:55:16 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-06 16:55:16 +0200 |
| commit | 6326030b7179580b934ba852b0fd98577bfb464a (patch) | |
| tree | ba44b32f456d888ab2adc8a86d3a94db916a380f /tests/test_mainwindow.cpp | |
| parent | 51b8fd5708d23108d532be1cf38e4bb619eeb777 (diff) | |
| download | qtmaildir-6326030b7179580b934ba852b0fd98577bfb464a.tar.gz qtmaildir-6326030b7179580b934ba852b0fd98577bfb464a.zip | |
fix: index the sent copy so it appears in the Sent view at once
ComposeWindow filed the sent copy into the account's sent folder and
discarded the path DraftStore::write() returned, using the result only to
test for failure. Nothing announced the file, so notmuch never learned it
existed, and the Sent view is a path query over the index rather than a
listing of the folder: the message was on disk and invisible until the
next notmuch new, which here is a cron tick up to ten minutes away.
Measured immediately after a send: 65 files in the account's Sent folder,
64 messages indexed for the same path.
This is item 158's defect one path over. That item established the rule
for drafts, and MainWindow wires both halves of it, so the send path was
already telling the worker to DROP the draft's entry while never telling
it to add the sent copy's. The missing half is the one the user sees.
A sentCopyFiled signal, emitted only where the write succeeded, connected
to the worker's existing indexDraftFile. That slot is generic despite its
name: it calls notmuch_database_index_file, applies nothing
draft-specific, and its previousPath already defaults to empty, which is
right for a copy that replaces nothing.
The connection is a lambda whose context object is m_worker, and that is
load-bearing. indexDraftFile takes two arguments where the signal carries
one, so a direct slot connection does not compile; the context object is
what queues the call onto the worker's thread and keeps notmuch off the
GUI thread. Simplifying it to a plain call reads as tidier and would
cross that boundary, so the comment says so.
The test asserts on the signal, on the file existing, and on it being
inside the Sent folder. Indexing itself is already covered against a real
database in test_notmuchworker; what was unproven was that anything ever
called it for a sent copy. Announcing a path that was never written is
the ghost entry removeIndexedFile exists to undo, which is why the
existence check is there.
Indexing is not repainting: a Sent view already on screen does not gain
the row from this, and whether it should refresh after a send is left as
a separate question.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jq9gXquUo9W4KXDagJXMmn
Diffstat (limited to 'tests/test_mainwindow.cpp')
| -rw-r--r-- | tests/test_mainwindow.cpp | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/tests/test_mainwindow.cpp b/tests/test_mainwindow.cpp index f20701e..f97b9bd 100644 --- a/tests/test_mainwindow.cpp +++ b/tests/test_mainwindow.cpp @@ -544,6 +544,7 @@ private slots: void aReplySeedsTheHtmlToggleFromTheOriginal(); void aNewMessageSeedsTheHtmlToggleFromConfig(); void disablingInputsCoversEveryFieldAndTheToolbar(); + void aFiledSentCopyIsAnnouncedForIndexing(); void aFailedSendCanBeRetriedWithoutFilingTheWrongCopy(); void anUnchangedMessageIsNotWrittenAgain(); void closingInsideTheDebounceStillSavesTheDraft(); @@ -15082,6 +15083,59 @@ void TestMainWindow::aNewMessageSeedsTheHtmlToggleFromConfig() "a Forward seeded from the original rather than from config"); } +/// Item 192. The sent copy must be announced so it can be indexed at once. +/// +/// The Sent view is a `path:` query over the INDEX, not a directory listing, +/// so a file notmuch has never seen is invisible there however correctly it +/// was written. Measured on real mail right after a send: 65 files in the Sent +/// folder, 64 messages indexed for the same path. Item 158 established this +/// for drafts and wired both halves; the send path was already telling the +/// worker to DROP the draft's entry while never telling it to add the sent +/// copy's. +/// +/// Asserted on the SIGNAL rather than on a notmuch query: the worker's +/// indexDraftFile() is already covered against a real database by +/// test_notmuchworker, so what is unproven here is that anything calls it. +void TestMainWindow::aFiledSentCopyIsAnnouncedForIndexing() +{ + ComposeFixture fixture; + QVERIFY(fixture.build(QStringLiteral("Drafts"), QStringLiteral("Sent"), + QStringLiteral("send_delay_ms=0"))); + + ComposeContext context = newContext(); + context.to = { QStringLiteral("someone@example.org") }; + + QPointer<ComposeWindow> window = + new ComposeWindow(context, fixture.config(), fixture.mailRoot()); + auto *body = window->findChild<QPlainTextEdit *>(QStringLiteral("body")); + QVERIFY(body); + body->setPlainText(QStringLiteral("Text.")); + + QSignalSpy filed(window, &ComposeWindow::sentCopyFiled); + + auto *sendAction = window->findChild<QAction *>(QStringLiteral("compose_send")); + QVERIFY(sendAction); + sendAction->trigger(); + + QTRY_VERIFY_WITH_TIMEOUT(window.isNull(), 15000); + + QCOMPARE(filed.size(), 1); + const QString announced = filed.first().first().toString(); + QVERIFY2(!announced.isEmpty(), "the sent copy was announced with no path"); + + // The path announced must be the file that was actually written, not the + // folder or a stale name: indexing a path that does not exist puts a ghost + // in the index, which is the defect removeIndexedFile() exists to undo. + QVERIFY2(QFile::exists(announced), + qPrintable(QStringLiteral("announced a path that does not exist: %1") + .arg(announced))); + const QString sentCur = + fixture.mailRoot() + QStringLiteral("/acct/Sent/cur"); + QVERIFY2(announced.startsWith(sentCur), + qPrintable(QStringLiteral("announced %1, which is not in %2") + .arg(announced, sentCur))); +} + void TestMainWindow::disablingInputsCoversEveryFieldAndTheToolbar() { ComposeFixture fixture; |
