mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-10 12:03:25 -08:00
[Tests] Use QtTest for model contracts and signal spies (#7630)
Qt6::Test was linked into every test but never used. Add a small RAII QAbstractItemModelTester helper and apply it to the deck list model, the card database model and display proxy, and the sets model. Add QSignalSpy coverage for the card-added and download-settings signals, and assert explicitly that a card row is a leaf with no child columns (the tester does not check that). The contract checker immediately found four model bugs, fixed here: - DeckListModel allowed children below non-zero columns. - CardDatabaseModel reported every card as a child of every card row. - CardDatabaseModel reported six columns for a valid (leaf) card index. - CardDatabaseDisplayModel claimed more rows were fetchable while rowCount already exposed them all, so fetchMore() inserted duplicates. Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
429eb2a1fd
commit
ce543896f5
9 changed files with 207 additions and 46 deletions
|
|
@ -33,8 +33,6 @@ CardDatabaseDisplayModel::CardDatabaseDisplayModel(QObject *parent)
|
|||
invalidate();
|
||||
emit modelDirty();
|
||||
});
|
||||
|
||||
loadedRowCount = 0;
|
||||
}
|
||||
|
||||
void CardDatabaseDisplayModel::setSourceModel(QAbstractItemModel *model)
|
||||
|
|
@ -45,10 +43,7 @@ void CardDatabaseDisplayModel::setSourceModel(QAbstractItemModel *model)
|
|||
|
||||
connect(model, &QAbstractItemModel::rowsRemoved, this, [this]() { dirty(); });
|
||||
|
||||
connect(model, &QAbstractItemModel::modelReset, this, [this]() {
|
||||
loadedRowCount = 0;
|
||||
dirty();
|
||||
});
|
||||
connect(model, &QAbstractItemModel::modelReset, this, [this]() { dirty(); });
|
||||
}
|
||||
|
||||
QMap<wchar_t, wchar_t> CardDatabaseDisplayModel::characterTranslation = {{L'“', L'\"'},
|
||||
|
|
@ -56,32 +51,6 @@ QMap<wchar_t, wchar_t> CardDatabaseDisplayModel::characterTranslation = {{L'“'
|
|||
{L'‘', L'\''},
|
||||
{L'’', L'\''}};
|
||||
|
||||
bool CardDatabaseDisplayModel::canFetchMore(const QModelIndex &index) const
|
||||
{
|
||||
return loadedRowCount < sourceModel()->rowCount(index);
|
||||
}
|
||||
|
||||
void CardDatabaseDisplayModel::fetchMore(const QModelIndex &index)
|
||||
{
|
||||
int remainder = sourceModel()->rowCount(index) - loadedRowCount;
|
||||
int itemsToFetch = qMin(100, remainder);
|
||||
|
||||
if (itemsToFetch == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto startIndex = qMin(rowCount(QModelIndex()), loadedRowCount);
|
||||
beginInsertRows(QModelIndex(), startIndex, startIndex + itemsToFetch - 1);
|
||||
|
||||
loadedRowCount += itemsToFetch;
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
int CardDatabaseDisplayModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return QSortFilterProxyModel::rowCount(parent);
|
||||
}
|
||||
|
||||
bool CardDatabaseDisplayModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
{
|
||||
const QString leftString = sourceModel()->data(left, CardDatabaseModel::SortRole).toString();
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ private:
|
|||
QSet<QString> cardNameSet, cardTypes, cardColors;
|
||||
FilterTree *filterTree;
|
||||
FilterString *filterString;
|
||||
int loadedRowCount;
|
||||
QTimer dirtyTimer;
|
||||
CardSearchLanguage searchLanguage;
|
||||
QString searchText;
|
||||
|
|
@ -85,9 +84,6 @@ public:
|
|||
dirtyTimer.start(20);
|
||||
}
|
||||
void clearFilterAll();
|
||||
[[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
[[nodiscard]] bool canFetchMore(const QModelIndex &parent) const override;
|
||||
void fetchMore(const QModelIndex &parent) override;
|
||||
signals:
|
||||
void modelDirty();
|
||||
|
||||
|
|
|
|||
|
|
@ -27,14 +27,18 @@ CardDatabaseModel::CardDatabaseModel(CardDatabase *_db, bool _showOnlyCardsFromE
|
|||
|
||||
CardDatabaseModel::~CardDatabaseModel() = default;
|
||||
|
||||
int CardDatabaseModel::rowCount(const QModelIndex & /*parent*/) const
|
||||
int CardDatabaseModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return cardList.size();
|
||||
// A list model's card rows are leaves; returning the full card count for a
|
||||
// valid parent makes every row claim all cards as children.
|
||||
return parent.isValid() ? 0 : cardList.size();
|
||||
}
|
||||
|
||||
int CardDatabaseModel::columnCount(const QModelIndex & /*parent*/) const
|
||||
int CardDatabaseModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return CARDDBMODEL_COLUMNS;
|
||||
// Card rows are leaves, so a valid parent holds no columns. Reporting the
|
||||
// row width for a card index would claim child cells that do not exist.
|
||||
return parent.isValid() ? 0 : CARDDBMODEL_COLUMNS;
|
||||
}
|
||||
|
||||
QVariant CardDatabaseModel::data(const QModelIndex &index, int role) const
|
||||
|
|
|
|||
|
|
@ -134,6 +134,13 @@ void DeckListModel::rebuildTree()
|
|||
|
||||
int DeckListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
// Only column 0 carries children. Column 1 and later indexes are siblings
|
||||
// used by views for the remaining cells of a row, and a model that hangs
|
||||
// children off them breaks QAbstractItemModelTester and proxy models.
|
||||
if (parent.isValid() && parent.column() != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// debugIndexInfo("rowCount", parent);
|
||||
auto *node = getNode<InnerDecklistNode *>(parent);
|
||||
if (node) {
|
||||
|
|
@ -282,7 +289,7 @@ QVariant DeckListModel::headerData(const int section, const Qt::Orientation orie
|
|||
QModelIndex DeckListModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
// debugIndexInfo("index", parent);
|
||||
if (!hasIndex(row, column, parent)) {
|
||||
if ((parent.isValid() && parent.column() != 0) || !hasIndex(row, column, parent)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue