2
#include "proxymodeltest.h"
6
#include "dynamictreemodel.h"
7
#include "../modeltest.h"
8
#include <QItemSelectionModel>
10
typedef QList<ModelChangeCommand*> CommandList;
12
Q_DECLARE_METATYPE( CommandList )
14
ModelSpy::ModelSpy(QObject *parent)
15
: QObject(parent), QList<QVariantList>()
17
qRegisterMetaType<QModelIndex>("QModelIndex");
18
qRegisterMetaType<IndexFinder>("IndexFinder");
21
void ModelSpy::setModel(AbstractProxyModel *model)
26
connect(m_model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
27
SLOT(rowsAboutToBeInserted(const QModelIndex &, int, int)));
28
connect(m_model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
29
SLOT(rowsInserted(const QModelIndex &, int, int)));
30
connect(m_model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
31
SLOT(rowsAboutToBeRemoved(const QModelIndex &, int, int)));
32
connect(m_model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
33
SLOT(rowsRemoved(const QModelIndex &, int, int)));
34
connect(m_model, SIGNAL(rowsAboutToBeMoved(const QModelIndex &, int, int,const QModelIndex &, int)),
35
SLOT(rowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
36
connect(m_model, SIGNAL(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)),
37
SLOT(rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)));
40
void ModelSpy::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
42
append(QVariantList() << RowsAboutToBeInserted << QVariant::fromValue(parent) << start << end);
45
void ModelSpy::rowsInserted(const QModelIndex &parent, int start, int end)
47
append(QVariantList() << RowsInserted << QVariant::fromValue(parent) << start << end);
50
void ModelSpy::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
52
append(QVariantList() << RowsAboutToBeRemoved << QVariant::fromValue(parent) << start << end);
55
void ModelSpy::rowsRemoved(const QModelIndex &parent, int start, int end)
57
append(QVariantList() << RowsRemoved << QVariant::fromValue(parent) << start << end);
60
void ModelSpy::rowsAboutToBeMoved(const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destStart)
62
append(QVariantList() << RowsAboutToBeMoved << QVariant::fromValue(srcParent) << start << end << QVariant::fromValue(destParent) << destStart);
65
void ModelSpy::rowsMoved(const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destStart)
67
append(QVariantList() << RowsMoved << QVariant::fromValue(srcParent) << start << end << QVariant::fromValue(destParent) << destStart);
70
void ModelSpy::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
72
append(QVariantList() << DataChanged << QVariant::fromValue(topLeft) << QVariant::fromValue(bottomRight));
76
ProxyModelTest::ProxyModelTest(QObject *parent)
77
: QObject(parent), m_model(new DynamicTreeModel(this)), m_proxyModel(0), m_modelSpy(new ModelSpy(this))
81
void ProxyModelTest::initTestCase()
85
DynamicTreeModel* ProxyModelTest::sourceModel()
91
QVariantList ProxyModelTest::getSignal(SignalType type, IndexFinder parentFinder, int start, int end)
93
return QVariantList() << type << QVariant::fromValue(parentFinder) << start << end;
96
void ProxyModelTest::signalInsertion(const QString &name, IndexFinder parentFinder, int startRow, int rowsAffected, int rowCount)
98
QVERIFY(startRow >= 0 && rowsAffected > 0);
99
QList<QVariantList> signalList;
100
signalList << getSignal(RowsAboutToBeInserted, parentFinder, startRow, startRow + rowsAffected - 1 );
101
signalList << getSignal(RowsInserted, parentFinder, startRow, startRow + rowsAffected - 1 );
103
QList<PersistentIndexChange> persistentList;
105
persistentList << getChange(parentFinder, startRow, rowCount - 1, rowsAffected);
107
setExpected(name, signalList, persistentList);
110
void ProxyModelTest::signalRemoval(const QString &name, IndexFinder parentFinder, int startRow, int rowsAffected, int rowCount)
112
QVERIFY(startRow >= 0 && rowsAffected > 0);
113
QList<QVariantList> signalList;
114
signalList << getSignal(RowsAboutToBeRemoved, parentFinder, startRow, startRow + rowsAffected - 1 );
115
signalList << getSignal(RowsRemoved, parentFinder, startRow, startRow + rowsAffected - 1 );
117
QList<PersistentIndexChange> persistentList;
120
persistentList << getChange(parentFinder, startRow, startRow + rowsAffected - 1, -1, true);
121
persistentList << getChange(parentFinder, startRow + rowsAffected, rowCount - 1, rowsAffected * -1 );
124
setExpected(name, signalList, persistentList);
127
void ProxyModelTest::noSignal(const QString &name)
129
QList<PersistentIndexChange> persistentList;
130
QList<QVariantList> signalList;
131
signalList << (QVariantList() << NoSignal);
132
signalList << (QVariantList() << NoSignal);
134
setExpected(name, signalList, persistentList);
137
PersistentIndexChange ProxyModelTest::getChange(IndexFinder parentFinder, int start, int end, int difference, bool toInvalid)
139
PersistentIndexChange change;
140
change.parentFinder = parentFinder;
141
change.startRow = start;
143
change.difference = difference;
144
change.toInvalid = toInvalid;
148
void ProxyModelTest::handleSignal(QVariantList expected)
150
int signalType = expected.takeAt(0).toInt();
151
if (NoSignal == signalType)
154
QVariantList result = getResultSignal();
155
QCOMPARE(result.takeAt(0).toInt(), signalType);
158
case RowsAboutToBeInserted:
160
case RowsAboutToBeRemoved:
163
QVERIFY( expected.size() == 3 );
164
IndexFinder parentFinder = qvariant_cast<IndexFinder>(expected.at(0));
165
QModelIndex parent = parentFinder.getIndex();
166
QCOMPARE(qvariant_cast<QModelIndex>(result.at(0)), parent );
167
QCOMPARE(result.at(1), expected.at(1) );
168
QCOMPARE(result.at(2), expected.at(2) );
171
case RowsAboutToBeMoved:
174
QVERIFY( expected.size() == 5 );
175
IndexFinder scrParentFinder = qvariant_cast<IndexFinder>(expected.at(0));
176
QModelIndex srcParent = scrParentFinder.getIndex();
177
QCOMPARE(qvariant_cast<QModelIndex>(result.at(0)), srcParent );
178
QCOMPARE(result.at(1), expected.at(1) );
179
QCOMPARE(result.at(2), expected.at(2) );
180
IndexFinder destParentFinder = qvariant_cast<IndexFinder>(expected.at(3));
181
QModelIndex destParent = destParentFinder.getIndex();
182
QCOMPARE(qvariant_cast<QModelIndex>(result.at(3)), destParent );
183
QCOMPARE(result.at(4), expected.at(4) );
187
QVERIFY( expected.size() == 2 );
188
IndexFinder topLeftFinder = qvariant_cast<IndexFinder>(expected.at(0));
189
QModelIndex topLeft = topLeftFinder.getIndex();
190
IndexFinder bottomRightFinder = qvariant_cast<IndexFinder>(expected.at(1));
191
QModelIndex bottomRight = bottomRightFinder.getIndex();
193
QVERIFY(topLeft.isValid() && bottomRight.isValid());
195
QCOMPARE(qvariant_cast<QModelIndex>(result.at(0)), topLeft );
196
QCOMPARE(qvariant_cast<QModelIndex>(result.at(0)), bottomRight );
202
QVariantList ProxyModelTest::getResultSignal()
204
return m_modelSpy->takeAt(0);
207
void ProxyModelTest::setProxyModel(AbstractProxyModel *proxyModel)
209
m_proxyModel = proxyModel;
210
m_proxyModel->setSourceModel(m_model);
211
m_modelSpy->setModel(m_proxyModel);
214
void ProxyModelTest::setExpected(const QString &name, const QList<QVariantList> &list, const QList<PersistentIndexChange> &persistentChanges)
216
m_expectedSignals.insert(name, list);
217
m_persistentChanges.insert(name, persistentChanges);
220
QModelIndexList ProxyModelTest::getDescendantIndexes(const QModelIndex &parent)
222
QModelIndexList list;
223
const int column = 0;
224
for(int row = 0; row < m_proxyModel->rowCount(parent); ++row)
226
QModelIndex idx = m_proxyModel->index(row, column, parent);
228
list << getDescendantIndexes(idx);
233
QList< QPersistentModelIndex > ProxyModelTest::toPersistent(QModelIndexList list)
235
QList<QPersistentModelIndex > persistentList;
236
foreach(QModelIndex idx, list)
238
persistentList << QPersistentModelIndex(idx);
240
return persistentList;
244
QModelIndexList ProxyModelTest::getUnchangedIndexes(const QModelIndex &parent, QList<QItemSelectionRange> ignoredRanges)
246
QModelIndexList list;
247
int rowCount = m_proxyModel->rowCount(parent);
248
for (int row = 0; row < rowCount; )
251
QModelIndex idx = m_proxyModel->index( row, column, parent);
253
foreach(QItemSelectionRange range, ignoredRanges)
255
if (range.topLeft().parent() == parent && range.topLeft().row() == idx.row())
257
row = range.bottomRight().row() + 1;
264
for (column = 0; column < m_proxyModel->columnCount(); ++column )
265
list << m_proxyModel->index( row, column, parent);
266
list << getUnchangedIndexes(idx, ignoredRanges);
274
void ProxyModelTest::doTest()
276
QFETCH( CommandList, commandList );
278
const char *currentTag = QTest::currentDataTag();
280
QVERIFY(currentTag != 0);
281
QVERIFY(m_expectedSignals.contains(currentTag));
282
QVERIFY(m_persistentChanges.contains(currentTag));
284
QList<QVariantList> signalList = m_expectedSignals.value(currentTag);
286
// Take persistent indexes.
287
QList<PersistentIndexChange> changeList = m_persistentChanges.value(currentTag);
289
QList<QPersistentModelIndex> persistentIndexes;
291
const int columnCount = m_model->columnCount();
292
QMutableListIterator<PersistentIndexChange> it(changeList);
294
QList<QItemSelectionRange> changedRanges;
297
PersistentIndexChange change = it.next();
298
QModelIndex parent = change.parentFinder.getIndex();
300
QVERIFY(change.startRow >= 0);
301
QVERIFY(change.endRow < m_proxyModel->rowCount(parent));
303
QModelIndex topLeft = m_proxyModel->index( change.startRow, 0, parent );
304
QModelIndex bottomRight = m_proxyModel->index( change.endRow, columnCount - 1, parent );
306
changedRanges << QItemSelectionRange(topLeft, bottomRight);
309
for (int row = change.startRow; row <= change.endRow; ++row )
311
for (int column = 0; column < columnCount; ++column)
313
QModelIndex idx = m_proxyModel->index(row, column, parent);
314
QVERIFY(idx.isValid());
315
change.indexes << idx;
316
change.persistentIndexes << QPersistentModelIndex(idx);
318
QModelIndex idx = m_proxyModel->index(row, 0, parent);
319
QModelIndexList descs = getDescendantIndexes(idx);
320
change.descendantIndexes << descs;
321
change.persistentDescendantIndexes << toPersistent(descs);
326
QModelIndexList unchangedIndexes = getUnchangedIndexes(QModelIndex(), changedRanges);
328
QList<QPersistentModelIndex> unchangedPersistentIndexes = toPersistent(unchangedIndexes);
330
foreach(ModelChangeCommand *command, commandList)
332
command->doCommand();
335
while (!signalList.isEmpty())
337
QVariantList expected = signalList.takeAt(0);
338
handleSignal(expected);
340
QVERIFY(m_modelSpy->isEmpty());
343
foreach (PersistentIndexChange change, changeList)
345
for (int i = 0; i < change.indexes.size(); i++)
347
QModelIndex idx = change.indexes.at(i);
348
QPersistentModelIndex persistentIndex = change.persistentIndexes.at(i);
349
if (change.toInvalid)
351
QVERIFY(!persistentIndex.isValid());
354
QCOMPARE(idx.row() + change.difference, persistentIndex.row());
355
QCOMPARE(idx.column(), persistentIndex.column());
356
QCOMPARE(idx.parent(), persistentIndex.parent());
359
for (int i = 0; i < change.descendantIndexes.size(); i++)
361
QModelIndex idx = change.descendantIndexes.at(i);
362
QPersistentModelIndex persistentIndex = change.persistentDescendantIndexes.at(i);
363
if (change.toInvalid)
365
QVERIFY(!persistentIndex.isValid());
368
QCOMPARE(idx.row(), persistentIndex.row());
369
QCOMPARE(idx.column(), persistentIndex.column());
370
QCOMPARE(idx.parent(), persistentIndex.parent());
373
for (int i = 0; i < unchangedIndexes.size(); ++i)
375
QModelIndex unchangedIdx = unchangedIndexes.at(i);
376
QPersistentModelIndex persistentIndex = unchangedPersistentIndexes.at(i);
377
QCOMPARE(unchangedIdx.row(), persistentIndex.row());
378
QCOMPARE(unchangedIdx.column(), persistentIndex.column());
379
QCOMPARE(unchangedIdx.parent(), persistentIndex.parent());
384
void ProxyModelTest::testInsertAndRemove_data()
386
QTest::addColumn<CommandList>("commandList");
388
CommandList commandList;
390
// Insert a single item at the top.
391
ModelInsertCommand *ins;
392
ins = new ModelInsertCommand(sourceModel(), this);
397
QTest::newRow("insert01") << commandList;
400
// Give the top level item 10 children.
401
ins = new ModelInsertCommand(m_model, this);
402
ins->setAncestorRowNumbers(QList<int>() << 0 );
408
QTest::newRow("insert02") << commandList;
411
// Give the top level item 10 'older' siblings.
412
ins = new ModelInsertCommand(m_model, this);
418
QTest::newRow("insert03") << commandList;
421
// Give the top level item 10 'younger' siblings.
422
ins = new ModelInsertCommand(m_model, this);
423
ins->setStartRow(11);
428
QTest::newRow("insert04") << commandList;
431
// Add more children to the top level item.
433
ins = new ModelInsertCommand(m_model, this);
434
ins->setAncestorRowNumbers(QList<int>() << 10 );
440
QTest::newRow("insert05") << commandList;
444
ins = new ModelInsertCommand(m_model, this);
445
ins->setAncestorRowNumbers(QList<int>() << 10 );
446
ins->setStartRow(20);
451
QTest::newRow("insert06") << commandList;
454
// Then somewhere in the middle.
455
ins = new ModelInsertCommand(m_model, this);
456
ins->setAncestorRowNumbers(QList<int>() << 10 );
457
ins->setStartRow(10);
462
QTest::newRow("insert07") << commandList;
465
// Add some more items for removing later.
466
ins = new ModelInsertCommand(m_model, this);
467
ins->setAncestorRowNumbers(QList<int>() << 10 << 5 );
471
ins = new ModelInsertCommand(m_model, this);
472
ins->setAncestorRowNumbers(QList<int>() << 10 << 5 << 5 );
476
ins = new ModelInsertCommand(m_model, this);
477
ins->setAncestorRowNumbers(QList<int>() << 10 << 5 << 5 << 5 );
481
ins = new ModelInsertCommand(m_model, this);
482
ins->setAncestorRowNumbers(QList<int>() << 10 << 6 );
486
ins = new ModelInsertCommand(m_model, this);
487
ins->setAncestorRowNumbers(QList<int>() << 10 << 7 );
492
QTest::newRow("insert08") << commandList;
495
ModelRemoveCommand *rem;
497
// Remove a single item without children.
498
rem = new ModelRemoveCommand(m_model, this);
499
rem->setAncestorRowNumbers(QList<int>() << 10 );
505
QTest::newRow("remove01") << commandList;
508
// Remove a single item with 10 children.
509
rem = new ModelRemoveCommand(m_model, this);
510
rem->setAncestorRowNumbers(QList<int>() << 10 );
516
QTest::newRow("remove02") << commandList;
519
// Remove a single item with no children from the top.
520
rem = new ModelRemoveCommand(m_model, this);
521
rem->setAncestorRowNumbers(QList<int>() << 10 << 5 );
527
QTest::newRow("remove03") << commandList;
530
// Remove a single second level item with no children from the bottom.
531
rem = new ModelRemoveCommand(m_model, this);
532
rem->setAncestorRowNumbers(QList<int>() << 10 << 5 );
538
QTest::newRow("remove04") << commandList;
541
// Remove a single second level item with no children from the middle.
542
rem = new ModelRemoveCommand(m_model, this);
543
rem->setAncestorRowNumbers(QList<int>() << 10 << 5 );
549
QTest::newRow("remove05") << commandList;
552
// clear the children of a second level item.
553
rem = new ModelRemoveCommand(m_model, this);
554
rem->setAncestorRowNumbers(QList<int>() << 10 << 5 );
560
QTest::newRow("remove06") << commandList;
564
rem = new ModelRemoveCommand(m_model, this);
565
rem->setAncestorRowNumbers(QList<int>() << 10 );
571
QTest::newRow("remove07") << commandList;