Files
RedBear-OS/local/recipes/kde/kf6-kitemmodels/source/autotests/kdescendantsproxymodeltest.cpp
T
2026-04-14 10:51:06 +01:00

766 lines
26 KiB
C++

/*
SPDX-FileCopyrightText: 2016 Sune Vuorela <sune@debian.org>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "kdescendantsproxymodel.h"
#include <QAbstractItemModelTester>
#include <QAbstractListModel>
#include <QIdentityProxyModel>
#include <QSignalSpy>
#include <QStandardItemModel>
#include <QTest>
struct Node {
~Node()
{
qDeleteAll(children);
}
QString label;
Node *parent = nullptr;
QList<Node *> children;
int knownChildren = 0;
};
class SimpleObjectModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit SimpleObjectModel(QObject *parent = nullptr, bool incremental = false);
~SimpleObjectModel() override;
QModelIndex index(int, int, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool insert(const QModelIndex &parent, int row, const QString &text);
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationRow) override;
Node *getRootNode() const
{
return m_root;
}
private:
Node *m_root;
// simulate a model that loads in new rows with fetchMore()
bool m_incremental;
};
SimpleObjectModel::SimpleObjectModel(QObject *parent, bool incremental)
: QAbstractListModel(parent)
, m_incremental(incremental)
{
m_root = new Node;
}
SimpleObjectModel::~SimpleObjectModel()
{
delete m_root;
}
QModelIndex SimpleObjectModel::index(int row, int col, const QModelIndex &parent) const
{
Node *parentItem;
if (!parent.isValid()) {
parentItem = static_cast<Node *>(m_root);
} else {
parentItem = static_cast<Node *>(parent.internalPointer());
}
if (row < 0 || parentItem->children.size() <= row) {
return QModelIndex();
}
Node *childItem = parentItem->children[row];
return createIndex(row, col, childItem);
}
QModelIndex SimpleObjectModel::parent(const QModelIndex &index) const
{
Node *childItem = static_cast<Node *>(index.internalPointer());
if (!childItem) {
return QModelIndex();
}
Node *parent = childItem->parent;
Node *grandParent = parent->parent;
int childRow = 0;
if (grandParent) {
childRow = grandParent->children.indexOf(parent);
}
if (parent == m_root) {
return QModelIndex();
}
return createIndex(childRow, 0, parent);
}
int SimpleObjectModel::rowCount(const QModelIndex &index) const
{
Node *item = static_cast<Node *>(index.internalPointer());
if (!item) {
item = m_root;
}
if (m_incremental) {
return item->knownChildren;
}
return item->children.count();
}
bool SimpleObjectModel::hasChildren(const QModelIndex &index) const
{
Node *item = static_cast<Node *>(index.internalPointer());
if (!item) {
item = m_root;
}
return !item->children.isEmpty();
}
QVariant SimpleObjectModel::data(const QModelIndex &index, int role) const
{
if (role != Qt::DisplayRole) {
return QVariant();
}
Node *node = static_cast<Node *>(index.internalPointer());
if (!node) {
return QVariant();
}
return node->label;
}
bool SimpleObjectModel::insert(const QModelIndex &index, int row, const QString &text)
{
if (row < 0) {
return false;
}
Node *parent = static_cast<Node *>(index.internalPointer());
if (!parent) {
parent = m_root;
}
if (row > parent->children.count()) {
return false;
}
beginInsertRows(index, row, row);
Node *child = new Node;
child->parent = parent;
child->label = text;
parent->children.insert(row, child);
endInsertRows();
return true;
}
bool SimpleObjectModel::removeRows(int row, int count, const QModelIndex &index)
{
if (row < 0) {
return false;
}
Node *parent = static_cast<Node *>(index.internalPointer());
if (!parent) {
parent = m_root;
}
const int last = row + count - 1;
if (last >= parent->children.count()) {
return false;
}
beginRemoveRows(index, row, last);
for (int i = last; i >= row; i--) {
Node *child = parent->children.takeAt(i);
delete child;
}
endRemoveRows();
return true;
}
bool SimpleObjectModel::moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationRow)
{
Node *sourceNode = static_cast<Node *>(sourceParent.internalPointer());
if (!sourceNode) {
sourceNode = m_root;
}
Node *destinationNode = static_cast<Node *>(destinationParent.internalPointer());
if (!destinationNode) {
destinationNode = m_root;
}
const int sourceLast = sourceRow + count - 1;
if (sourceNode != destinationNode) {
if (count <= 0 || sourceRow < 0 || sourceRow >= sourceNode->children.count() || destinationRow < 0
|| destinationRow > destinationNode->children.count()) {
return false;
}
if (!beginMoveRows(sourceParent, sourceRow, sourceLast, destinationParent, destinationRow)) {
return false;
}
Node *child = sourceNode->children.takeAt(sourceRow);
child->parent = destinationNode;
destinationNode->children.insert(destinationRow, child);
endMoveRows();
return true;
}
if (count <= 0 || sourceRow == destinationRow || sourceRow < 0 || sourceRow >= destinationNode->children.count() || destinationRow < 0
|| destinationRow > destinationNode->children.count() || count - destinationRow > destinationNode->children.count() - sourceRow) {
return false;
}
// beginMoveRows wants indexes before the source rows are removed from the old order
if (!beginMoveRows(sourceParent, sourceRow, sourceLast, destinationParent, destinationRow)) {
return false;
}
if (sourceRow < destinationRow) {
for (int i = count - 1; i >= 0; --i) {
destinationNode->children.move(sourceRow + i, destinationRow - count + i);
}
} else {
for (int i = 0; i < count; ++i) {
destinationNode->children.move(sourceRow + i, destinationRow + i);
}
}
endMoveRows();
return true;
}
class tst_KDescendantProxyModel : public QObject
{
Q_OBJECT
std::unique_ptr<QStandardItemModel> createTree(const QString &prefix)
{
/*
* |- parent1
* | |- child1
* | `- child2
* `- parent2
* |- child1
* `- child2
*/
auto model = std::make_unique<QStandardItemModel>(this);
for (int i = 0; i < 2; i++) {
QStandardItem *item = new QStandardItem();
item->setData(QString(prefix + QString::number(i)), Qt::DisplayRole);
for (int j = 0; j < 2; j++) {
QStandardItem *child = new QStandardItem();
child->setData(QString(prefix + QString::number(i) + "-" + QString::number(j)), Qt::DisplayRole);
item->appendRow(child);
}
model->appendRow(item);
}
return model;
}
private Q_SLOTS:
void testResetModelContent();
void testSourceModelReset();
void testChangeSeparator();
void testChangeInvisibleSeparator();
void testRemoveSeparator();
void testResetCollapsedModelContent();
void testInsertInCollapsedModel();
void testRemoveInCollapsedModel();
void testMoveInsideCollapsed();
void testExpandInsideCollapsed();
void testEmptyModel();
void testEmptyChild();
};
/// Tests that replacing the source model results in data getting changed
void tst_KDescendantProxyModel::testResetModelContent()
{
auto model1 = createTree("FirstModel");
KDescendantsProxyModel proxy;
new QAbstractItemModelTester(&proxy);
proxy.setSourceModel(model1.get());
QCOMPARE(proxy.rowCount(), 6);
{
// clang-format off
const QStringList results {
"FirstModel0",
"FirstModel0-0",
"FirstModel0-1",
"FirstModel1",
"FirstModel1-0",
"FirstModel1-1"
};
// clang-format on
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
auto model2 = createTree("SecondModel");
{
proxy.setSourceModel(model2.get());
// clang-format off
const QStringList results {
"SecondModel0",
"SecondModel0-0",
"SecondModel0-1",
"SecondModel1",
"SecondModel1-0",
"SecondModel1-1"
};
// clang-format on
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
}
/// Tests that a reset in the source model results in data getting changed
void tst_KDescendantProxyModel::testSourceModelReset()
{
auto model1 = createTree("FirstModel");
KDescendantsProxyModel proxy;
new QAbstractItemModelTester(&proxy); // ensure no nested signals
QIdentityProxyModel identityProxy;
identityProxy.setSourceModel(model1.get());
proxy.setSourceModel(&identityProxy);
QCOMPARE(proxy.rowCount(), 6);
{
// clang-format off
const QStringList results {
"FirstModel0",
"FirstModel0-0",
"FirstModel0-1",
"FirstModel1",
"FirstModel1-0",
"FirstModel1-1"
};
// clang-format on
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
auto model2 = createTree("SecondModel");
{
identityProxy.setSourceModel(model2.get()); // This makes QIdentityProxyModel emit a reset
// clang-format off
const QStringList results {
"SecondModel0",
"SecondModel0-0",
"SecondModel0-1",
"SecondModel1",
"SecondModel1-0",
"SecondModel1-1"
};
// clang-format on
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
}
/// tests that change separator works, as well as emits the relevant data changed signals
void tst_KDescendantProxyModel::testChangeSeparator()
{
auto model1 = createTree("FirstModel");
KDescendantsProxyModel proxy;
new QAbstractItemModelTester(&proxy);
proxy.setSourceModel(model1.get());
proxy.setDisplayAncestorData(true);
QSignalSpy dataChangedSpy(&proxy, &QAbstractItemModel::dataChanged);
QCOMPARE(proxy.rowCount(), 6);
{
QStringList results = QStringList() << "FirstModel0"
<< "FirstModel0 / FirstModel0-0"
<< "FirstModel0 / FirstModel0-1"
<< "FirstModel1"
<< "FirstModel1 / FirstModel1-0"
<< "FirstModel1 / FirstModel1-1";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
proxy.setAncestorSeparator("LOL");
QCOMPARE(dataChangedSpy.count(), 1);
{
QStringList results = QStringList() << "FirstModel0"
<< "FirstModel0LOLFirstModel0-0"
<< "FirstModel0LOLFirstModel0-1"
<< "FirstModel1"
<< "FirstModel1LOLFirstModel1-0"
<< "FirstModel1LOLFirstModel1-1";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
}
/// tests that change separator that is not shown does not change the content and does not
/// emit data changed signals, since the data isn't changed
void tst_KDescendantProxyModel::testChangeInvisibleSeparator()
{
auto model1 = createTree("FirstModel");
KDescendantsProxyModel proxy;
new QAbstractItemModelTester(&proxy);
proxy.setSourceModel(model1.get());
QSignalSpy dataChangedSpy(&proxy, &QAbstractItemModel::dataChanged);
QCOMPARE(proxy.rowCount(), 6);
{
QStringList results = QStringList() << "FirstModel0"
<< "FirstModel0-0"
<< "FirstModel0-1"
<< "FirstModel1"
<< "FirstModel1-0"
<< "FirstModel1-1";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
proxy.setAncestorSeparator("LOL");
QCOMPARE(dataChangedSpy.count(), 0);
{
QStringList results = QStringList() << "FirstModel0"
<< "FirstModel0-0"
<< "FirstModel0-1"
<< "FirstModel1"
<< "FirstModel1-0"
<< "FirstModel1-1";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
}
/// tests that data is properly updated when separator is removed/hidden
/// and data changed signal is emitted
void tst_KDescendantProxyModel::testRemoveSeparator()
{
auto model1 = createTree("FirstModel");
KDescendantsProxyModel proxy;
new QAbstractItemModelTester(&proxy);
proxy.setSourceModel(model1.get());
QSignalSpy dataChangedSpy(&proxy, &QAbstractItemModel::dataChanged);
proxy.setDisplayAncestorData(true);
QCOMPARE(dataChangedSpy.count(), 1);
dataChangedSpy.clear();
QCOMPARE(proxy.rowCount(), 6);
{
QStringList results = QStringList() << "FirstModel0"
<< "FirstModel0 / FirstModel0-0"
<< "FirstModel0 / FirstModel0-1"
<< "FirstModel1"
<< "FirstModel1 / FirstModel1-0"
<< "FirstModel1 / FirstModel1-1";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
proxy.setDisplayAncestorData(false);
QCOMPARE(dataChangedSpy.count(), 1);
{
QStringList results = QStringList() << "FirstModel0"
<< "FirstModel0-0"
<< "FirstModel0-1"
<< "FirstModel1"
<< "FirstModel1-0"
<< "FirstModel1-1";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
}
void tst_KDescendantProxyModel::testResetCollapsedModelContent()
{
auto model1 = createTree("FirstModel");
KDescendantsProxyModel proxy;
new QAbstractItemModelTester(&proxy);
proxy.setExpandsByDefault(false);
proxy.setSourceModel(model1.get());
QCOMPARE(proxy.rowCount(), 2);
{
QStringList results = QStringList() << "FirstModel0"
<< "FirstModel1";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
{
QModelIndex idx = model1->index(0, 0);
proxy.expandSourceIndex(idx);
QStringList results = QStringList() << "FirstModel0"
<< "FirstModel0-0"
<< "FirstModel0-1"
<< "FirstModel1";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
{
QModelIndex idx = model1->index(1, 0);
proxy.expandSourceIndex(idx);
QStringList results = QStringList() << "FirstModel0"
<< "FirstModel0-0"
<< "FirstModel0-1"
<< "FirstModel1"
<< "FirstModel1-0"
<< "FirstModel1-1";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
auto model2 = createTree("SecondModel");
{
proxy.setSourceModel(model2.get());
QModelIndex idx = model2->index(0, 0);
proxy.expandSourceIndex(idx);
idx = model2->index(1, 0);
proxy.expandSourceIndex(idx);
QStringList results = QStringList() << "SecondModel0"
<< "SecondModel0-0"
<< "SecondModel0-1"
<< "SecondModel1"
<< "SecondModel1-0"
<< "SecondModel1-1";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
}
void tst_KDescendantProxyModel::testInsertInCollapsedModel()
{
auto model1 = createTree("Model");
KDescendantsProxyModel proxy;
proxy.setExpandsByDefault(false);
proxy.setSourceModel(model1.get());
QCOMPARE(proxy.rowCount(), 2);
QSignalSpy insertSpy(&proxy, &QAbstractItemModel::rowsInserted);
QCOMPARE(insertSpy.count(), 0);
QStandardItem *parent = model1->item(0, 0);
QVERIFY(parent);
QStandardItem *child = new QStandardItem();
child->setData(QString(QStringLiteral("Model") + QString::number(0) + "-" + QString::number(2)), Qt::DisplayRole);
parent->appendRow(child);
// Adding a child to the collapsed parent doesn't have an effect to the proxy
QCOMPARE(proxy.rowCount(), 2);
QCOMPARE(insertSpy.count(), 0);
// If we expand everything inserted should be here
QModelIndex idx = model1->index(0, 0);
proxy.expandSourceIndex(idx);
QCOMPARE(proxy.rowCount(), 5);
QCOMPARE(insertSpy.count(), 1);
QCOMPARE(proxy.index(3, 0).data(Qt::DisplayRole).toString(), QStringLiteral("Model0-2"));
// Add another child to the expanded node, now the proxy is affected immediately
child = new QStandardItem();
child->setData(QString(QStringLiteral("Model") + QString::number(0) + "-" + QString::number(3)), Qt::DisplayRole);
parent->appendRow(child);
QCOMPARE(proxy.rowCount(), 6);
QCOMPARE(insertSpy.count(), 2);
}
void tst_KDescendantProxyModel::testRemoveInCollapsedModel()
{
auto model1 = createTree("Model");
KDescendantsProxyModel proxy;
proxy.setExpandsByDefault(false);
proxy.setSourceModel(model1.get());
QCOMPARE(proxy.rowCount(), 2);
QSignalSpy removeSpy(&proxy, &QAbstractItemModel::rowsRemoved);
QCOMPARE(removeSpy.count(), 0);
QStandardItem *parent = model1->item(0, 0);
QVERIFY(parent);
parent->removeRow(0);
// Adding a child to the collapsed parent doesn't have an effect to the proxy
QCOMPARE(proxy.rowCount(), 2);
QCOMPARE(removeSpy.count(), 0);
// If we expand everything inserted should be here
QModelIndex idx = model1->index(0, 0);
proxy.expandSourceIndex(idx);
QCOMPARE(proxy.rowCount(), 3);
QCOMPARE(proxy.index(1, 0).data(Qt::DisplayRole).toString(), QStringLiteral("Model0-1"));
parent->removeRow(0);
QCOMPARE(proxy.rowCount(), 2);
QCOMPARE(removeSpy.count(), 1);
idx = model1->index(1, 0);
proxy.expandSourceIndex(idx);
QCOMPARE(proxy.rowCount(), 4);
}
void tst_KDescendantProxyModel::testMoveInsideCollapsed()
{
SimpleObjectModel *model = new SimpleObjectModel(this);
model->insert(QModelIndex(), 0, QStringLiteral("Model0"));
model->insert(QModelIndex(), 1, QStringLiteral("Model1"));
model->insert(QModelIndex(), 2, QStringLiteral("Model2"));
model->insert(model->index(0, 0, QModelIndex()), 0, QStringLiteral("Model0-0"));
model->insert(model->index(1, 0, QModelIndex()), 0, QStringLiteral("Model1-0"));
QCOMPARE(model->rowCount(), 3);
KDescendantsProxyModel proxy;
proxy.setExpandsByDefault(false);
proxy.setSourceModel(model);
QCOMPARE(proxy.rowCount(), 3);
QSignalSpy removeSpy(&proxy, &QAbstractItemModel::rowsRemoved);
QCOMPARE(removeSpy.count(), 0);
QSignalSpy insertSpy(&proxy, &QAbstractItemModel::rowsInserted);
QCOMPARE(insertSpy.count(), 0);
model->moveRows(QModelIndex(), 2, 1, model->index(0, 0, QModelIndex()), 1);
QCOMPARE(removeSpy.count(), 1);
QVERIFY(!removeSpy.first()[0].value<QModelIndex>().isValid());
QCOMPARE(removeSpy.first()[1].toInt(), 2);
QCOMPARE(removeSpy.first()[2].toInt(), 2);
QCOMPARE(model->rowCount(), 2);
QCOMPARE(proxy.rowCount(), 2);
model->moveRows(model->index(0, 0, QModelIndex()), 0, 1, QModelIndex(), 1);
QCOMPARE(insertSpy.count(), 1);
QCOMPARE(model->rowCount(), 3);
QCOMPARE(proxy.rowCount(), 3);
QVERIFY(!insertSpy.first()[0].value<QModelIndex>().isValid());
QCOMPARE(insertSpy.first()[1].toInt(), 1);
QCOMPARE(insertSpy.first()[2].toInt(), 1);
QModelIndex idx = model->index(0, 0);
proxy.expandSourceIndex(idx);
idx = model->index(1, 0);
proxy.expandSourceIndex(idx);
idx = model->index(2, 0);
proxy.expandSourceIndex(idx);
QStringList results = QStringList() << "Model0"
<< "Model2"
<< "Model0-0"
<< "Model1"
<< "Model1-0";
QCOMPARE(proxy.rowCount(), results.count());
for (int i = 0; i < proxy.rowCount(); i++) {
QCOMPARE(proxy.index(i, 0).data(Qt::DisplayRole).toString(), results[i]);
}
}
void tst_KDescendantProxyModel::testExpandInsideCollapsed()
{
SimpleObjectModel *model = new SimpleObjectModel(this);
model->insert(QModelIndex(), 0, QStringLiteral("Model0"));
model->insert(QModelIndex(), 1, QStringLiteral("Model1"));
model->insert(QModelIndex(), 2, QStringLiteral("Model2"));
auto parentIndex = model->index(0, 0, QModelIndex());
model->insert(parentIndex, 0, QStringLiteral("Model0-0"));
auto childIndex = model->index(0, 0, parentIndex);
model->insert(childIndex, 0, QStringLiteral("Model0-0-0"));
QCOMPARE(model->rowCount(), 3);
KDescendantsProxyModel proxy;
proxy.setExpandsByDefault(false);
proxy.setSourceModel(model);
QCOMPARE(proxy.rowCount(), 3);
proxy.expandSourceIndex(childIndex);
QVERIFY(proxy.isSourceIndexExpanded(childIndex));
QVERIFY(!proxy.isSourceIndexExpanded(parentIndex));
QCOMPARE(proxy.rowCount(), 3);
proxy.expandSourceIndex(parentIndex);
QCOMPARE(proxy.rowCount(), 5);
}
void tst_KDescendantProxyModel::testEmptyModel()
{
SimpleObjectModel *model = new SimpleObjectModel(this, true);
model->insert(QModelIndex(), 0, QStringLiteral("Row0"));
model->insert(QModelIndex(), 0, QStringLiteral("Row1"));
KDescendantsProxyModel proxy;
new QAbstractItemModelTester(&proxy);
proxy.setSourceModel(model);
QCOMPARE(proxy.rowCount(), 0);
}
void tst_KDescendantProxyModel::testEmptyChild()
{
SimpleObjectModel *model = new SimpleObjectModel(this, true);
model->insert(QModelIndex(), 0, QStringLiteral("Row0"));
auto parentIndex = model->index(0, 0, QModelIndex());
model->insert(parentIndex, 0, QStringLiteral("Row0-0"));
model->insert(parentIndex, 0, QStringLiteral("Row0-1"));
model->insert(QModelIndex(), 0, QStringLiteral("Row1"));
// simulate that the row count for the root node is known because it was listed
model->getRootNode()->knownChildren = 2;
KDescendantsProxyModel proxy;
new QAbstractItemModelTester(&proxy);
proxy.setSourceModel(model);
proxy.setExpandsByDefault(false);
QCOMPARE(proxy.rowCount(), 2);
// remove the row that has children but a rowCount of 0
model->removeRows(0, 1, QModelIndex());
QCOMPARE(proxy.rowCount(), 1);
}
QTEST_MAIN(tst_KDescendantProxyModel)
#include "kdescendantsproxymodeltest.moc"