From 63c7a1fcaadb1e26c1597d5b86ce85066890ece3 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 1 Oct 2026 10:31:52 +0200 Subject: fix: open a conversation's first message from the overview Clicking the first message in a conversation overview's unread list did nothing visible. applyPendingDashboardSelection() matched the conversation row on the root's message id, so it reselected the row that was already current and the overview stayed on screen. Since item 177 setThreadMessages keeps a conversation's first message as child 0, so it has a row of its own. Only a thread of one now answers for its message on its own row, the same guard 236ac86 added to the recovery. AGENTS.md still said a thread's first message is never among its children, which has been true only for a thread of one since item 177. It is corrected to say so. Co-Authored-By: Claude Opus 5.5 --- tests/test_mainwindow.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'tests') diff --git a/tests/test_mainwindow.cpp b/tests/test_mainwindow.cpp index 0aaf8ff..7ef89e7 100644 --- a/tests/test_mainwindow.cpp +++ b/tests/test_mainwindow.cpp @@ -390,6 +390,7 @@ private slots: void recoveringAStaleThreadQueriesTheWholeThread(); void recoveryReselectsTheMessageThatWasBeingRead(); void recoveryOnTheFirstMessageSelectsItsOwnRow(); + void aDashboardEntryForTheFirstMessageSelectsItsOwnRow(); void doubleClickingAThreadOpensThatThreadAlone(); void doubleClickingAReplyOpensItsThreadNotTheReplyAlone(); void doubleClickingDoesNotLeaveTheMarkReadTimerArmed(); @@ -3538,6 +3539,60 @@ void TestMainWindow::recoveryOnTheFirstMessageSelectsItsOwnRow() QCOMPARE(model->threadFor(current).threadId, QStringLiteral("T1")); } +void TestMainWindow::aDashboardEntryForTheFirstMessageSelectsItsOwnRow() +{ + // The dashboard's unread list can name the conversation's FIRST message. + // Since item 177 that message is child 0 with a row of its own, so the + // entry must land there. Matching the conversation row on the root's id + // reselected the row already current, and the click did nothing visible. + const Config config; + MainWindow window(config); + + auto *queryEdit = window.findChild(); + QVERIFY(queryEdit); + queryEdit->setText(QStringLiteral("tag:unread")); + queryEdit->returnPressed(); + const quint64 generation = window.currentGenerationForTesting(); + + auto *model = window.findChild(); + QVERIFY(model); + auto *view = window.findChild(); + QVERIFY(view); + + ThreadSummary thread = makeThread(QStringLiteral("T1"), {}); + thread.totalCount = 2; + const QVector result{ thread }; + QMetaObject::invokeMethod(&window, "onThreadsReady", + Q_ARG(QVector, result), + Q_ARG(quint64, generation)); + view->setCurrentIndex(model->index(0, 0, QModelIndex())); + QVERIFY(model->isConversationRow(view->currentIndex())); + + QMetaObject::invokeMethod(&window, "selectMessageInCurrentThread", + Q_ARG(QString, QStringLiteral("m0@example.org"))); + + MessageNode root; + root.messageId = QStringLiteral("m0@example.org"); + root.threadId = QStringLiteral("T1"); + root.depth = 0; + MessageNode reply; + reply.messageId = QStringLiteral("m1@example.org"); + reply.threadId = QStringLiteral("T1"); + reply.depth = 1; + const QVector nodes{ root, reply }; + QMetaObject::invokeMethod(&window, "onThreadTreeLoaded", + Q_ARG(QVector, nodes), + Q_ARG(quint64, generation)); + + const QModelIndex current = view->currentIndex(); + QVERIFY2(current.isValid(), "the entry selected nothing"); + QVERIFY2(model->isMessageRow(current), + "the first message landed on the conversation row, which keeps " + "the dashboard on screen"); + QCOMPARE(model->messageAt(current).messageId, + QStringLiteral("m0@example.org")); +} + void TestMainWindow::doubleClickingAThreadOpensThatThreadAlone() { // Item 91, the thread case: "double click on a thread loads the whole -- cgit v1.2.3