diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test_mainwindow.cpp | 293 |
1 files changed, 243 insertions, 50 deletions
diff --git a/tests/test_mainwindow.cpp b/tests/test_mainwindow.cpp index 5031ead..7b6e55d 100644 --- a/tests/test_mainwindow.cpp +++ b/tests/test_mainwindow.cpp @@ -38,6 +38,7 @@ #include <QSplitter> #include <QTableView> #include <QToolBar> +#include <QTreeView> #include <QTimer> #include "config.h" @@ -47,6 +48,7 @@ #include "notmuchworker.h" #include "tagchip.h" #include "threadlistmodel.h" +#include "threadlistview.h" /// MainWindow is mostly wiring, and the parts that need a real database are /// still verified manually. What is checked here is the action registry: the @@ -94,6 +96,8 @@ private slots: void theStatusBarFollowsTheSyncPhase(); void aSelectedReadThreadIsNotDimmedIntoTheHighlight(); void thePillRowSpansTheWholeWidthNotOneColumn(); + void childRowsAreIndentedUnderTheirThread(); + void noTagStripIsPaintedUnderAMessageRow(); void markAllReadIsDisabledUntilTheQueryFinishes(); void markAllReadActsOnEveryRowAndUndoesInOneStep(); void markAllReadDoesNothingWhenNothingIsUnread(); @@ -452,7 +456,7 @@ void TestMainWindow::headerStateFromADifferentColumnLayoutIsDiscarded() const Config config; MainWindow reopened(config); - auto *view = reopened.findChild<QTableView *>(); + auto *view = reopened.findChild<QTreeView *>(); QVERIFY(view); QCOMPARE(view->columnWidth(ThreadListModel::AttachmentColumn), 28); QCOMPARE(view->columnWidth(ThreadListModel::DateColumn), 130); @@ -503,6 +507,27 @@ void TestMainWindow::returnInTheQueryBarRunsTheQueryNotOpenThread() QVERIFY(!actionFired); } +/// Selects a top-level THREAD row, replacing QTableView::selectRow which a +/// QTreeView does not have. +/// +/// Not merely a rename: setCurrentIndex alone leaves the selection model empty, +/// and select() alone leaves current invalid, so every test asserting on either +/// would break in a different way. Both are set here, exactly as +/// QTableView::selectRow did. +static void selectThreadRow(QTreeView *view, int row) +{ + const QModelIndex index = view->model()->index(row, 0, QModelIndex()); + view->selectionModel()->select( + index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + view->setCurrentIndex(index); +} + +/// The height of a top-level row, replacing QTableView::rowHeight(int). +static int threadRowHeight(QTreeView *view, int row) +{ + return view->visualRect(view->model()->index(row, 0, QModelIndex())).height(); +} + /// A thread summary carrying the tags a test needs. Enough to drive selection; /// nothing here touches a database. static ThreadSummary makeThread(const QString &id, const QStringList &tags) @@ -530,7 +555,7 @@ void TestMainWindow::thePillRowSpansTheWholeWidthNotOneColumn() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); ThreadSummary thread = makeThread(QStringLiteral("t1"), {}); @@ -576,7 +601,7 @@ void TestMainWindow::thePillRowSpansTheWholeWidthNotOneColumn() for (const QVariant &colour : colours) pillColours.insert(colour.value<QColor>().rgb()); - const int rowHeight = view->rowHeight(0); + const int rowHeight = threadRowHeight(view, 0); QVERIFY(rowHeight > 0); int chipPixels = 0; @@ -592,6 +617,174 @@ void TestMainWindow::thePillRowSpansTheWholeWidthNotOneColumn() "still confined to that cell rather than spanning the row"); } +void TestMainWindow::childRowsAreIndentedUnderTheirThread() +{ + const Config config; + MainWindow window(config); + + auto *model = window.findChild<ThreadListModel *>(); + QVERIFY(model); + auto *view = window.findChild<QTreeView *>(); + QVERIFY2(view, "the thread list is not a QTreeView, so it cannot indent"); + + model->appendBatch({ makeThread(QStringLiteral("t1"), {}) }); + + MessageNode first; + first.messageId = QStringLiteral("m0@example.org"); + first.threadId = QStringLiteral("t1"); + first.depth = 0; + MessageNode reply; + reply.messageId = QStringLiteral("m1@example.org"); + reply.threadId = QStringLiteral("t1"); + reply.from = QStringLiteral("A Replier <replier@example.org>"); + reply.depth = 1; + model->setThreadMessages(QStringLiteral("t1"), { first, reply }); + + window.resize(1400, 300); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + const QModelIndex root = model->index(0, 0, QModelIndex()); + view->expand(root); + QApplication::processEvents(); + + // Measured on the TREE POSITION column, not on column 0. A QTreeView + // indents only the column carrying the expander, verified against Qt 6.11: + // with setTreePosition(4), column 0 reports the same left edge for a thread + // and its reply (0 and 0) while column 4 reports 420 and 440. Asserting on + // column 0 therefore fails against a perfectly indented tree. + const int treeColumn = ThreadListModel::SubjectColumn; + const QModelIndex rootCell = model->index(0, treeColumn, QModelIndex()); + const QModelIndex child = model->index(0, treeColumn, root); + QVERIFY(child.isValid()); + + // Guards before the claim: a probe that cannot see both rows can report + // anything it likes about their relative position. + QVERIFY2(view->visualRect(rootCell).height() > 0, + "the thread row has no height, so nothing about it is measurable"); + QVERIFY2(view->visualRect(child).height() > 0, + "the reply row has no height: it is collapsed or off-screen, and " + "an indent test against it would pass without drawing anything"); + + QVERIFY2(view->visualRect(child).left() > view->visualRect(rootCell).left(), + "the reply is not indented relative to its thread"); +} + +void TestMainWindow::noTagStripIsPaintedUnderAMessageRow() +{ + // The strip is a row-wide band of the THREAD's tags. Painted under every + // reply as well it would stripe the list and repeat identical tags down the + // whole expansion. + // + // TWO independent guards stop that, and this test is aimed at the SECOND: + // the model returns no pills for a child row, and the view skips child rows + // in its walk. Asserting against the real model tests only the first, and + // the view's guard can be deleted without the test noticing: verified by + // mutation, which passed with the skip removed. So the model is replaced + // here by one that hands out pills for EVERY row, thread and reply alike, + // leaving the view's own skip as the only thing that can keep the reply + // rows clean. + /// Hands out the same pills for a message row as for a thread row, which + /// the real model never does. Without this the view's skip is unobservable. + class PillsEverywhereModel : public ThreadListModel + { + public: + QVariant data(const QModelIndex &index, int role) const override + { + if (role == PillTagsRole) { + return QStringList{ QStringLiteral("mailing-list/SBo"), + QStringLiteral("signed") }; + } + if (role == PillColoursRole) { + return QVariantList{ QVariant::fromValue(QColor(Qt::magenta)), + QVariant::fromValue(QColor(Qt::cyan)) }; + } + return ThreadListModel::data(index, role); + } + }; + + PillsEverywhereModel model; + ThreadListView view; + view.setModel(&model); + view.setTreePosition(ThreadListModel::SubjectColumn); + view.setUniformRowHeights(true); + + // The delegates MainWindow installs, and not optional here. The strip's + // band is measured against SubjectDelegate::rowHeightFor; without the + // delegate the rows take the default height, the band overflows into the + // row below, and the thread's own strip paints across the reply. That + // reads exactly like a missing skip in the walk and is not one. + view.setItemDelegate(new RowStyleDelegate(&view)); + view.setItemDelegateForColumn(ThreadListModel::SubjectColumn, + new SubjectDelegate(&view)); + view.setColumnWidth(ThreadListModel::AttachmentColumn, 28); + view.setColumnWidth(ThreadListModel::FlagColumn, 28); + view.setColumnWidth(ThreadListModel::DateColumn, 130); + view.setColumnWidth(ThreadListModel::AuthorsColumn, 180); + view.setColumnWidth(ThreadListModel::SubjectColumn, 520); + + ThreadSummary thread = makeThread(QStringLiteral("t1"), {}); + thread.tags = QStringList{ QStringLiteral("mailing-list/SBo"), + QStringLiteral("signed") }; + model.appendBatch({ thread }); + + MessageNode first; + first.messageId = QStringLiteral("m0@example.org"); + first.threadId = QStringLiteral("t1"); + first.depth = 0; + MessageNode reply; + reply.messageId = QStringLiteral("m1@example.org"); + reply.threadId = QStringLiteral("t1"); + reply.depth = 1; + model.setThreadMessages(QStringLiteral("t1"), { first, reply }); + + view.resize(1400, 300); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + const QModelIndex root = model.index(0, 0, QModelIndex()); + view.expand(root); + QApplication::processEvents(); + + const QModelIndex child = model.index(0, 0, root); + const QRect childRect = view.visualRect(child); + QVERIFY2(childRect.height() > 0, "the reply row is not on screen"); + + // The exact colours the stub supplies, so an antialiased edge of anything + // else cannot be counted as a pill. + QSet<QRgb> pillColours; + pillColours.insert(QColor(Qt::magenta).rgb()); + pillColours.insert(QColor(Qt::cyan).rgb()); + + QImage shot(view.viewport()->size(), QImage::Format_ARGB32); + shot.fill(Qt::transparent); + view.viewport()->render(&shot); + + // Guard proving the probe can see pills at all: the THREAD row must have + // them, or a zero count under the reply proves nothing about the reply. + const QRect rootRect = view.visualRect(root); + int threadPills = 0; + for (int y = rootRect.top(); y < qMin(rootRect.bottom(), shot.height()); ++y) { + for (int x = 0; x < shot.width(); ++x) { + if (pillColours.contains(shot.pixel(x, y) | 0xff000000)) + ++threadPills; + } + } + QVERIFY2(threadPills > 0, + "no pill pixels under the THREAD row either, so this probe cannot " + "tell a missing strip from a broken render"); + + int replyPills = 0; + for (int y = childRect.top(); y < qMin(childRect.bottom(), shot.height()); ++y) { + for (int x = 0; x < shot.width(); ++x) { + if (pillColours.contains(shot.pixel(x, y) | 0xff000000)) + ++replyPills; + } + } + + QCOMPARE(replyPills, 0); +} + void TestMainWindow::aSelectedReadThreadIsNotDimmedIntoTheHighlight() { // Read threads carry a dimmed Qt::ForegroundRole, blended against the @@ -607,7 +800,7 @@ void TestMainWindow::aSelectedReadThreadIsNotDimmedIntoTheHighlight() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); // Both rows READ, so both are dimmed and neither is bold: the only thing @@ -633,10 +826,10 @@ void TestMainWindow::aSelectedReadThreadIsNotDimmedIntoTheHighlight() // dimmed row switches it to the highlight's own text colour, so the two // rows MUST differ; comparing two identically-styled rows would pass // against a delegate that did nothing at all. - view->selectRow(0); + selectThreadRow(view, 0); QApplication::processEvents(); - const int rowHeight = view->rowHeight(0); + const int rowHeight = threadRowHeight(view, 0); QVERIFY(rowHeight > 0); QImage shot(view->viewport()->size(), QImage::Format_ARGB32); @@ -724,7 +917,7 @@ void TestMainWindow::markAllReadActsOnEveryRowAndUndoesInOneStep() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *action = window.findChild<QAction *>(QStringLiteral("mark_all_read")); QVERIFY(action); @@ -746,7 +939,7 @@ void TestMainWindow::markAllReadActsOnEveryRowAndUndoesInOneStep() // One row selected, to prove the action ignores the selection rather than // acting on it. - view->selectRow(0); + selectThreadRow(view, 0); action->trigger(); @@ -831,7 +1024,7 @@ void TestMainWindow::markReadTimerRestartsRatherThanStacking() QVERIFY(model); auto *timer = window.findChild<QTimer *>(QStringLiteral("markReadTimer")); QVERIFY(timer); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); model->appendBatch({ makeThread(QStringLiteral("t1"), @@ -841,13 +1034,13 @@ void TestMainWindow::markReadTimerRestartsRatherThanStacking() makeThread(QStringLiteral("t3"), { QStringLiteral("unread") }) }); - view->selectRow(0); + selectThreadRow(view, 0); QVERIFY2(timer->isActive(), "no timer armed for an unread thread"); // Move on before it can fire. One timer stays armed, not three. - view->selectRow(1); + selectThreadRow(view, 1); QVERIFY(timer->isActive()); - view->selectRow(2); + selectThreadRow(view, 2); QVERIFY(timer->isActive()); // Exactly one timer exists at all, which is what "restarted, not stacked" @@ -867,7 +1060,7 @@ void TestMainWindow::markReadTimerIsNotArmedForAReadThread() QVERIFY(model); auto *timer = window.findChild<QTimer *>(QStringLiteral("markReadTimer")); QVERIFY(timer); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); model->appendBatch({ makeThread(QStringLiteral("read"), @@ -875,16 +1068,16 @@ void TestMainWindow::markReadTimerIsNotArmedForAReadThread() makeThread(QStringLiteral("unread"), { QStringLiteral("unread") }) }); - view->selectRow(0); + selectThreadRow(view, 0); QVERIFY2(!timer->isActive(), "armed a timer for an already-read thread"); // And the unread one still arms, so this is not "never arms". - view->selectRow(1); + selectThreadRow(view, 1); QVERIFY(timer->isActive()); // Moving back to a read thread disarms it again, rather than leaving the // previous thread's timer running to fire against the wrong row. - view->selectRow(0); + selectThreadRow(view, 0); QVERIFY(!timer->isActive()); } @@ -909,12 +1102,12 @@ void TestMainWindow::markReadCanBeDisabled() QVERIFY(model); auto *timer = window.findChild<QTimer *>(QStringLiteral("markReadTimer")); QVERIFY(timer); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); model->appendBatch({ makeThread(QStringLiteral("t1"), { QStringLiteral("unread") }) }); - view->selectRow(0); + selectThreadRow(view, 0); QVERIFY2(!timer->isActive(), "a negative mark_read_delay_ms must disable the timer"); @@ -1091,7 +1284,7 @@ void TestMainWindow::selectAllIsBoundAndSelectsEveryRow() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); model->appendBatch({ makeThread(QStringLiteral("t1"), {}), @@ -1120,7 +1313,7 @@ void TestMainWindow::aMultiRowSelectionDoesNotArmTheMarkReadTimer() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *timer = window.findChild<QTimer *>(QStringLiteral("markReadTimer")); QVERIFY(timer); @@ -1134,7 +1327,7 @@ void TestMainWindow::aMultiRowSelectionDoesNotArmTheMarkReadTimer() // Sweep down as Shift+arrow does: current moves onto a row while the // selection already spans more than one. - view->selectRow(0); + selectThreadRow(view, 0); view->selectionModel()->select( model->index(1, 0), QItemSelectionModel::Select | QItemSelectionModel::Rows); @@ -1159,7 +1352,7 @@ void TestMainWindow::growingASelectionCancelsAnAlreadyArmedTimer() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *timer = window.findChild<QTimer *>(QStringLiteral("markReadTimer")); QVERIFY(timer); @@ -1169,7 +1362,7 @@ void TestMainWindow::growingASelectionCancelsAnAlreadyArmedTimer() makeThread(QStringLiteral("t2"), { QStringLiteral("unread") }) }); - view->selectRow(0); + selectThreadRow(view, 0); QVERIFY2(timer->isActive(), "no timer armed for a single unread thread"); // Extend to a second row, as Shift+click would. @@ -1191,7 +1384,7 @@ void TestMainWindow::collapsingBackToOneRowLoadsThatThreadAgain() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *timer = window.findChild<QTimer *>(QStringLiteral("markReadTimer")); QVERIFY(timer); @@ -1205,7 +1398,7 @@ void TestMainWindow::collapsingBackToOneRowLoadsThatThreadAgain() QVERIFY(!timer->isActive()); // Back to one row, as a plain click would leave it. - view->selectRow(1); + selectThreadRow(view, 1); QVERIFY2(timer->isActive(), "collapsing back to one row did not resume mark-read"); @@ -1221,7 +1414,7 @@ void TestMainWindow::theStatusBarReportsAMultiRowSelection() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *status = window.findChild<QLabel *>(QStringLiteral("statusMessage")); QVERIFY2(status, "no status label to report into"); @@ -1246,7 +1439,7 @@ void TestMainWindow::clearSelectionBlanksThePaneAndDeselects() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); model->appendBatch({ makeThread(QStringLiteral("t1"), {}), @@ -1256,7 +1449,7 @@ void TestMainWindow::clearSelectionBlanksThePaneAndDeselects() // and what CLAUDE.md requires: selectAll() on a fresh view emits no // currentRowChanged at all, so a test starting there passes against a // missing guard. - view->selectRow(0); + selectThreadRow(view, 0); QCOMPARE(view->selectionModel()->selectedRows().size(), 1); auto *action = window.findChild<QAction *>(QStringLiteral("clear_selection")); @@ -1302,13 +1495,13 @@ void TestMainWindow::clearPaneLeavesTheSelectionAlone() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); model->appendBatch({ makeThread(QStringLiteral("t1"), {}), makeThread(QStringLiteral("t2"), {}) }); - view->selectRow(0); + selectThreadRow(view, 0); QCOMPARE(view->selectionModel()->selectedRows().size(), 1); auto *action = window.findChild<QAction *>(QStringLiteral("clear_pane")); @@ -1421,7 +1614,7 @@ void TestMainWindow::theThreadListOffersAContextMenu() const Config config; MainWindow window(config); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); QCOMPARE(view->contextMenuPolicy(), Qt::CustomContextMenu); @@ -1464,7 +1657,7 @@ void TestMainWindow::aSecondRowBlanksThePaneNotOnlyAThird() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *timer = window.findChild<QTimer *>(QStringLiteral("markReadTimer")); QVERIFY(timer); @@ -1477,7 +1670,7 @@ void TestMainWindow::aSecondRowBlanksThePaneNotOnlyAThird() { QStringLiteral("unread") }) }); // One row: ordinary reading, so a timer is armed and a thread is current. - view->selectRow(0); + selectThreadRow(view, 0); QCOMPARE(view->selectionModel()->selectedRows().size(), 1); QVERIFY(timer->isActive()); @@ -1829,13 +2022,13 @@ void TestMainWindow::escapeBlanksTheMessagePane() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); model->appendBatch({ makeThread(QStringLiteral("t1"), {}), makeThread(QStringLiteral("t2"), {}) }); - view->selectRow(0); + selectThreadRow(view, 0); QVERIFY2(!window.currentThreadId().isEmpty(), "no thread was opened to blank"); @@ -1856,14 +2049,14 @@ void TestMainWindow::deleteTogglesOnAnAlreadyDeletedThread() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *action = window.findChild<QAction *>(QStringLiteral("delete")); QVERIFY(action); model->appendBatch({ makeThread(QStringLiteral("t1"), { QStringLiteral("deleted") }) }); - view->selectRow(0); + selectThreadRow(view, 0); action->trigger(); @@ -1884,7 +2077,7 @@ void TestMainWindow::deleteOnAMixedSelectionDeletesRatherThanSplittingIt() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *action = window.findChild<QAction *>(QStringLiteral("delete")); QVERIFY(action); @@ -1935,7 +2128,7 @@ void TestMainWindow::theSelectionCountIsStateAndDoesNotExpire() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *status = window.findChild<QLabel *>(QStringLiteral("statusMessage")); QVERIFY(status); @@ -2059,13 +2252,13 @@ void TestMainWindow::anEditDuringABackgroundSyncIsNotSentYet() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *action = window.findChild<QAction *>(QStringLiteral("flag")); QVERIFY2(action, "no flag action registered"); model->appendBatch({ makeThread(QStringLiteral("t1"), {}) }); - view->selectRow(0); + selectThreadRow(view, 0); // A cron sync takes the lock. QMetaObject::invokeMethod(&window, "onExternalSyncStateChanged", @@ -2090,13 +2283,13 @@ void TestMainWindow::aHeldEditIsSentWhenTheBackgroundSyncEnds() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *action = window.findChild<QAction *>(QStringLiteral("flag")); QVERIFY(action); model->appendBatch({ makeThread(QStringLiteral("t1"), {}) }); - view->selectRow(0); + selectThreadRow(view, 0); QMetaObject::invokeMethod(&window, "onExternalSyncStateChanged", Q_ARG(SyncMonitor::State, @@ -2125,7 +2318,7 @@ void TestMainWindow::aHeldEditCountsAsUnsynced() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *action = window.findChild<QAction *>(QStringLiteral("flag")); QVERIFY(action); @@ -2134,7 +2327,7 @@ void TestMainWindow::aHeldEditCountsAsUnsynced() QVERIFY2(label->isHidden(), "the indicator starts hidden at zero"); model->appendBatch({ makeThread(QStringLiteral("t1"), {}) }); - view->selectRow(0); + selectThreadRow(view, 0); QMetaObject::invokeMethod(&window, "onExternalSyncStateChanged", Q_ARG(SyncMonitor::State, @@ -2162,7 +2355,7 @@ void TestMainWindow::anUnreadableLockTableStillSendsTheEdit() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *action = window.findChild<QAction *>(QStringLiteral("flag")); QVERIFY(action); @@ -2173,7 +2366,7 @@ void TestMainWindow::anUnreadableLockTableStillSendsTheEdit() QMetaObject::invokeMethod(&window, "onExternalSyncStateChanged", Q_ARG(SyncMonitor::State, SyncMonitor::State::Running)); - view->selectRow(0); + selectThreadRow(view, 0); action->trigger(); QVERIFY2(window.hasEditAwaitingSend(), "the edit was not held during a running sync, so this test is not " @@ -2189,7 +2382,7 @@ void TestMainWindow::anUnreadableLockTableStillSendsTheEdit() "platform without /proc/locks"); // And a NEW edit is sent rather than held. - view->selectRow(1); + selectThreadRow(view, 1); action->trigger(); QVERIFY2(!window.hasEditAwaitingSend(), "an unreadable lock table held a new edit, so writes never resume"); @@ -2206,7 +2399,7 @@ void TestMainWindow::aRejectedWriteKeepsEarlierUndoHistory() auto *model = window.findChild<ThreadListModel *>(); QVERIFY(model); - auto *view = window.findChild<QTableView *>(); + auto *view = window.findChild<QTreeView *>(); QVERIFY(view); auto *flag = window.findChild<QAction *>(QStringLiteral("flag")); QVERIFY(flag); @@ -2215,7 +2408,7 @@ void TestMainWindow::aRejectedWriteKeepsEarlierUndoHistory() model->appendBatch({ makeThread(QStringLiteral("t1"), { QStringLiteral("inbox") }) }); - view->selectRow(0); + selectThreadRow(view, 0); // One edit that succeeds, so there is history worth keeping. archive->trigger(); |
