File indexing completed on 2024-04-28 15:27:49
0001 /* 0002 This file is part of the test suite of the Qt Toolkit. 0003 0004 SPDX-FileCopyrightText: 2013 Digia Plc and/or its subsidiary(-ies) <https://www.qt.io/terms-conditions/> 0005 SPDX-FileCopyrightText: 2010 Stephen Kelly <steveire@gmail.com> 0006 0007 SPDX-License-Identifier: LGPL-2.1-only 0008 */ 0009 0010 #include "modeltest.h" 0011 0012 #include <QTest> 0013 0014 /*! 0015 Connect to all of the models signals. Whenever anything happens recheck everything. 0016 */ 0017 ModelTest::ModelTest(QAbstractItemModel *_model, Mode testType, QObject *parent) 0018 : QObject(parent) 0019 , model(_model) 0020 , fetchingMore(false) 0021 , pedantic(testType == Pedantic) 0022 { 0023 init(); 0024 if (pedantic) { 0025 refreshStatus(); 0026 // This is almost certainly not needed. 0027 // connect(QAbstractEventDispatcher::instance(), SIGNAL(awake()), SLOT(ensureSteady())); 0028 } 0029 } 0030 0031 ModelTest::ModelTest(QAbstractItemModel *_model, QObject *parent) 0032 : QObject(parent) 0033 , model(_model) 0034 , fetchingMore(false) 0035 , pedantic(false) 0036 { 0037 init(); 0038 } 0039 0040 void ModelTest::init() 0041 { 0042 if (!model) { 0043 qFatal("%s: model must not be null", Q_FUNC_INFO); 0044 } 0045 0046 connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)), this, SLOT(runAllTests())); 0047 connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)), this, SLOT(runAllTests())); 0048 connect(model, SIGNAL(columnsInserted(QModelIndex, int, int)), this, SLOT(runAllTests())); 0049 connect(model, SIGNAL(columnsRemoved(QModelIndex, int, int)), this, SLOT(runAllTests())); 0050 connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(runAllTests())); 0051 connect(model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)), this, SLOT(runAllTests())); 0052 connect(model, SIGNAL(layoutAboutToBeChanged()), this, SLOT(runAllTests())); 0053 connect(model, SIGNAL(layoutChanged()), this, SLOT(runAllTests())); 0054 connect(model, SIGNAL(modelReset()), this, SLOT(runAllTests())); 0055 connect(model, SIGNAL(modelAboutToBeReset()), this, SLOT(modelAboutToBeReset())); 0056 connect(model, SIGNAL(modelReset()), this, SLOT(modelReset())); 0057 connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), this, SLOT(runAllTests())); 0058 connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), this, SLOT(runAllTests())); 0059 connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(runAllTests())); 0060 connect(model, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(runAllTests())); 0061 0062 // Special checks for changes 0063 connect(model, SIGNAL(layoutAboutToBeChanged()), this, SLOT(layoutAboutToBeChanged())); 0064 connect(model, SIGNAL(layoutChanged()), this, SLOT(layoutChanged())); 0065 0066 connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), this, SLOT(rowsAboutToBeInserted(QModelIndex, int, int))); 0067 connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), this, SLOT(rowsAboutToBeRemoved(QModelIndex, int, int))); 0068 connect(model, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(rowsInserted(QModelIndex, int, int))); 0069 connect(model, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(rowsRemoved(QModelIndex, int, int))); 0070 connect(model, 0071 SIGNAL(rowsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int)), 0072 this, 0073 SLOT(rowsAboutToBeMoved(QModelIndex, int, int, QModelIndex, int))); 0074 connect(model, SIGNAL(rowsMoved(QModelIndex, int, int, QModelIndex, int)), this, SLOT(rowsMoved(QModelIndex, int, int, QModelIndex, int))); 0075 connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(dataChanged(QModelIndex, QModelIndex))); 0076 connect(model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)), this, SLOT(headerDataChanged(Qt::Orientation, int, int))); 0077 0078 runAllTests(); 0079 } 0080 0081 void ModelTest::runAllTests() 0082 { 0083 if (fetchingMore) { 0084 return; 0085 } 0086 nonDestructiveBasicTest(); 0087 rowCount(); 0088 columnCount(); 0089 hasIndex(); 0090 index(); 0091 parent(); 0092 data(); 0093 } 0094 0095 /*! 0096 nonDestructiveBasicTest tries to call a number of the basic functions (not all) 0097 to make sure the model doesn't outright segfault, testing the functions that makes sense. 0098 */ 0099 void ModelTest::nonDestructiveBasicTest() 0100 { 0101 QVERIFY(model->buddy(QModelIndex()) == QModelIndex()); 0102 model->canFetchMore(QModelIndex()); 0103 QVERIFY(model->columnCount(QModelIndex()) >= 0); 0104 QVERIFY(model->data(QModelIndex()) == QVariant()); 0105 fetchingMore = true; 0106 model->fetchMore(QModelIndex()); 0107 fetchingMore = false; 0108 Qt::ItemFlags flags = model->flags(QModelIndex()); 0109 QVERIFY(flags == Qt::ItemIsDropEnabled || flags == 0); 0110 model->hasChildren(QModelIndex()); 0111 model->hasIndex(0, 0); 0112 model->headerData(0, Qt::Horizontal); 0113 model->index(0, 0); 0114 model->itemData(QModelIndex()); 0115 QVariant cache; 0116 model->match(QModelIndex(), -1, cache); 0117 model->mimeTypes(); 0118 QVERIFY(model->parent(QModelIndex()) == QModelIndex()); 0119 QVERIFY(model->rowCount() >= 0); 0120 QVariant variant; 0121 model->setData(QModelIndex(), variant, -1); 0122 model->setHeaderData(-1, Qt::Horizontal, QVariant()); 0123 model->setHeaderData(999999, Qt::Horizontal, QVariant()); 0124 QMap<int, QVariant> roles; 0125 model->sibling(0, 0, QModelIndex()); 0126 model->span(QModelIndex()); 0127 model->supportedDropActions(); 0128 } 0129 0130 /*! 0131 Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren() 0132 0133 Models that are dynamically populated are not as fully tested here. 0134 */ 0135 void ModelTest::rowCount() 0136 { 0137 // qDebug() << "rc"; 0138 // check top row 0139 QModelIndex topIndex = model->index(0, 0, QModelIndex()); 0140 int rows = model->rowCount(topIndex); 0141 QVERIFY(rows >= 0); 0142 QCOMPARE(model->hasChildren(topIndex), rows > 0); 0143 0144 QModelIndex secondLevelIndex = model->index(0, 0, topIndex); 0145 if (secondLevelIndex.isValid()) { // not the top level 0146 // check a row count where parent is valid 0147 rows = model->rowCount(secondLevelIndex); 0148 QVERIFY(rows >= 0); 0149 if (rows > 0) { 0150 QVERIFY(model->hasChildren(secondLevelIndex)); 0151 } 0152 } 0153 0154 // The models rowCount() is tested more extensively in checkChildren(), 0155 // but this catches the big mistakes 0156 } 0157 0158 /*! 0159 Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren() 0160 */ 0161 void ModelTest::columnCount() 0162 { 0163 // check top row 0164 QModelIndex topIndex = model->index(0, 0, QModelIndex()); 0165 QVERIFY(model->columnCount(topIndex) >= 0); 0166 0167 // check a column count where parent is valid 0168 QModelIndex childIndex = model->index(0, 0, topIndex); 0169 if (childIndex.isValid()) { 0170 QVERIFY(model->columnCount(childIndex) >= 0); 0171 } 0172 0173 // columnCount() is tested more extensively in checkChildren(), 0174 // but this catches the big mistakes 0175 } 0176 0177 /*! 0178 Tests model's implementation of QAbstractItemModel::hasIndex() 0179 */ 0180 void ModelTest::hasIndex() 0181 { 0182 // qDebug() << "hi"; 0183 // Make sure that invalid values returns an invalid index 0184 QVERIFY(!model->hasIndex(-2, -2)); 0185 QVERIFY(!model->hasIndex(-2, 0)); 0186 QVERIFY(!model->hasIndex(0, -2)); 0187 0188 int rows = model->rowCount(); 0189 int columns = model->columnCount(); 0190 0191 // check out of bounds 0192 QVERIFY(!model->hasIndex(rows, columns)); 0193 QVERIFY(!model->hasIndex(rows + 1, columns + 1)); 0194 0195 QCOMPARE(model->hasIndex(0, 0), rows > 0); 0196 0197 // hasIndex() is tested more extensively in checkChildren(), 0198 // but this catches the big mistakes 0199 } 0200 0201 /*! 0202 Tests model's implementation of QAbstractItemModel::index() 0203 */ 0204 void ModelTest::index() 0205 { 0206 // qDebug() << "i"; 0207 // Make sure that invalid values returns an invalid index 0208 QVERIFY(model->index(-2, -2) == QModelIndex()); 0209 QVERIFY(model->index(-2, 0) == QModelIndex()); 0210 QVERIFY(model->index(0, -2) == QModelIndex()); 0211 0212 int rows = model->rowCount(); 0213 int columns = model->columnCount(); 0214 0215 if (rows == 0) { 0216 return; 0217 } 0218 0219 // Catch off by one errors 0220 QVERIFY(model->index(rows, columns) == QModelIndex()); 0221 QVERIFY(model->index(0, 0).isValid()); 0222 0223 // Make sure that the same index is *always* returned 0224 QModelIndex a = model->index(0, 0); 0225 QModelIndex b = model->index(0, 0); 0226 QVERIFY(a == b); 0227 0228 // index() is tested more extensively in checkChildren(), 0229 // but this catches the big mistakes 0230 } 0231 0232 /*! 0233 Tests model's implementation of QAbstractItemModel::parent() 0234 */ 0235 void ModelTest::parent() 0236 { 0237 // qDebug() << "p"; 0238 // Make sure the model won't crash and will return an invalid QModelIndex 0239 // when asked for the parent of an invalid index. 0240 QVERIFY(model->parent(QModelIndex()) == QModelIndex()); 0241 0242 if (model->rowCount() == 0) { 0243 return; 0244 } 0245 0246 // Column 0 | Column 1 | 0247 // QModelIndex() | | 0248 // \- topIndex | topIndex1 | 0249 // \- childIndex | childIndex1 | 0250 0251 // Common error test #1, make sure that a top level index has a parent 0252 // that is a invalid QModelIndex. 0253 QModelIndex topIndex = model->index(0, 0, QModelIndex()); 0254 QVERIFY(model->parent(topIndex) == QModelIndex()); 0255 0256 // Common error test #2, make sure that a second level index has a parent 0257 // that is the first level index. 0258 if (model->rowCount(topIndex) > 0) { 0259 QModelIndex childIndex = model->index(0, 0, topIndex); 0260 if (model->parent(childIndex) != topIndex) { 0261 qDebug() << model->parent(childIndex) << topIndex << topIndex.data(); 0262 } 0263 QVERIFY(model->parent(childIndex) == topIndex); 0264 } 0265 0266 // Common error test #3, the second column should NOT have the same children 0267 // as the first column in a row. 0268 // Usually the second column shouldn't have children. 0269 QModelIndex topIndex1 = model->index(0, 1, QModelIndex()); 0270 if (model->rowCount(topIndex1) > 0) { 0271 QModelIndex childIndex = model->index(0, 0, topIndex); 0272 QModelIndex childIndex1 = model->index(0, 0, topIndex1); 0273 QVERIFY(childIndex != childIndex1); 0274 } 0275 0276 // Full test, walk n levels deep through the model making sure that all 0277 // parent's children correctly specify their parent. 0278 checkChildren(QModelIndex()); 0279 } 0280 0281 /*! 0282 Called from the parent() test. 0283 0284 A model that returns an index of parent X should also return X when asking 0285 for the parent of the index. 0286 0287 This recursive function does pretty extensive testing on the whole model in an 0288 effort to catch edge cases. 0289 0290 This function assumes that rowCount(), columnCount() and index() already work. 0291 If they have a bug it will point it out, but the above tests should have already 0292 found the basic bugs because it is easier to figure out the problem in 0293 those tests then this one. 0294 */ 0295 void ModelTest::checkChildren(const QModelIndex &parent, int currentDepth) 0296 { 0297 // First just try walking back up the tree. 0298 QModelIndex p = parent; 0299 while (p.isValid()) { 0300 p = p.parent(); 0301 } 0302 0303 // For models that are dynamically populated 0304 if (model->canFetchMore(parent)) { 0305 fetchingMore = true; 0306 model->fetchMore(parent); 0307 fetchingMore = false; 0308 } 0309 0310 int rows = model->rowCount(parent); 0311 int columns = model->columnCount(parent); 0312 0313 // Some further testing against rows(), columns(), and hasChildren() 0314 QVERIFY(rows >= 0); 0315 QVERIFY(columns >= 0); 0316 QCOMPARE(model->hasChildren(parent), rows > 0); 0317 0318 qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows << "columns:" << columns << "parent column:" << parent.column(); 0319 0320 const QModelIndex topLeftChild = model->index(0, 0, parent); 0321 0322 QVERIFY(!model->hasIndex(rows, 0, parent)); 0323 QVERIFY(!model->index(rows, 0, parent).isValid()); 0324 for (int r = 0; r < rows; ++r) { 0325 if (model->canFetchMore(parent)) { 0326 fetchingMore = true; 0327 model->fetchMore(parent); 0328 fetchingMore = false; 0329 } 0330 QVERIFY(!model->hasIndex(r, columns, parent)); 0331 QVERIFY(!model->index(r, columns, parent).isValid()); 0332 for (int c = 0; c < columns; ++c) { 0333 QVERIFY(model->hasIndex(r, c, parent)); 0334 QModelIndex index = model->index(r, c, parent); 0335 // rowCount() and columnCount() said that it existed... 0336 QVERIFY(index.isValid()); 0337 0338 // index() should always return the same index when called twice in a row 0339 QModelIndex modifiedIndex = model->index(r, c, parent); 0340 QVERIFY(index == modifiedIndex); 0341 0342 // Make sure we get the same index if we request it twice in a row 0343 QModelIndex a = model->index(r, c, parent); 0344 QModelIndex b = model->index(r, c, parent); 0345 QVERIFY(a == b); 0346 0347 { 0348 const QModelIndex sibling = model->sibling(r, c, topLeftChild); 0349 QVERIFY(index == sibling); 0350 } 0351 { 0352 const QModelIndex sibling = topLeftChild.sibling(r, c); 0353 QVERIFY(index == sibling); 0354 } 0355 0356 // Some basic checking on the index that is returned 0357 QVERIFY(index.model() == model); 0358 QCOMPARE(index.row(), r); 0359 QCOMPARE(index.column(), c); 0360 // While you can technically return a QVariant usually this is a sign 0361 // of a bug in data(). Disable if this really is ok in your model. 0362 if (!model->data(index, Qt::DisplayRole).isValid()) { 0363 qDebug() << index << index.data() << index.parent(); 0364 } 0365 QVERIFY(model->data(index, Qt::DisplayRole).isValid()); 0366 0367 // If the next test fails here is some somewhat useful debug you play with. 0368 0369 /* 0370 if (model->parent(index) != parent) { 0371 qDebug() << r << c << currentDepth << model->data(index).toString() 0372 << model->data(parent).toString(); 0373 qDebug() << index << parent << model->parent(index); 0374 // And a view that you can even use to show the model. 0375 // QTreeView view; 0376 // view.setModel(model); 0377 // view.show(); 0378 }*/ 0379 0380 // Check that we can get back our real parent. 0381 QCOMPARE(model->parent(index), parent); 0382 0383 // recursively go down the children 0384 if (model->hasChildren(index) && currentDepth < 10) { 0385 // qDebug() << r << c << "has children" << model->rowCount(index); 0386 checkChildren(index, ++currentDepth); 0387 } /* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/ 0388 0389 // make sure that after testing the children that the index doesn't change. 0390 QModelIndex newerIndex = model->index(r, c, parent); 0391 QVERIFY(index == newerIndex); 0392 } 0393 } 0394 } 0395 0396 /*! 0397 Tests model's implementation of QAbstractItemModel::data() 0398 */ 0399 void ModelTest::data() 0400 { 0401 // Invalid index should return an invalid qvariant 0402 QVERIFY(!model->data(QModelIndex()).isValid()); 0403 0404 if (model->rowCount() == 0) { 0405 return; 0406 } 0407 0408 // A valid index should have a valid QVariant data 0409 QVERIFY(model->index(0, 0).isValid()); 0410 0411 // shouldn't be able to set data on an invalid index 0412 QVERIFY(!model->setData(QModelIndex(), QLatin1String("foo"), Qt::DisplayRole)); 0413 0414 // General Purpose roles that should return a QString 0415 QVariant variant = model->data(model->index(0, 0), Qt::ToolTipRole); 0416 if (variant.isValid()) { 0417 QVERIFY(variant.canConvert<QString>()); 0418 } 0419 variant = model->data(model->index(0, 0), Qt::StatusTipRole); 0420 if (variant.isValid()) { 0421 QVERIFY(variant.canConvert<QString>()); 0422 } 0423 variant = model->data(model->index(0, 0), Qt::WhatsThisRole); 0424 if (variant.isValid()) { 0425 QVERIFY(variant.canConvert<QString>()); 0426 } 0427 0428 // General Purpose roles that should return a QSize 0429 variant = model->data(model->index(0, 0), Qt::SizeHintRole); 0430 if (variant.isValid()) { 0431 QVERIFY(variant.canConvert<QSize>()); 0432 } 0433 0434 // General Purpose roles that should return a QFont 0435 QVariant fontVariant = model->data(model->index(0, 0), Qt::FontRole); 0436 if (fontVariant.isValid()) { 0437 QVERIFY(fontVariant.canConvert<QFont>()); 0438 } 0439 0440 // Check that the alignment is one we know about 0441 QVariant textAlignmentVariant = model->data(model->index(0, 0), Qt::TextAlignmentRole); 0442 if (textAlignmentVariant.isValid()) { 0443 const auto alignment = textAlignmentVariant.toUInt(); 0444 QCOMPARE(alignment, (alignment & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask))); 0445 } 0446 0447 // General Purpose roles that should return a QColor 0448 QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundRole); 0449 if (colorVariant.isValid()) { 0450 QVERIFY(colorVariant.canConvert<QColor>()); 0451 } 0452 0453 colorVariant = model->data(model->index(0, 0), Qt::ForegroundRole); 0454 if (colorVariant.isValid()) { 0455 QVERIFY(colorVariant.canConvert<QColor>()); 0456 } 0457 0458 // Check that the "check state" is one we know about. 0459 QVariant checkStateVariant = model->data(model->index(0, 0), Qt::CheckStateRole); 0460 if (checkStateVariant.isValid()) { 0461 int state = checkStateVariant.toInt(); 0462 QVERIFY(state == Qt::Unchecked || state == Qt::PartiallyChecked || state == Qt::Checked); 0463 } 0464 } 0465 0466 /*! 0467 Store what is about to be inserted to make sure it actually happens 0468 0469 \sa rowsInserted() 0470 */ 0471 void ModelTest::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) 0472 { 0473 // Q_UNUSED(end); 0474 qDebug() << "rowsAboutToBeInserted" 0475 << "start=" << start << "end=" << end << "parent=" << model->data(parent).toString() 0476 << "current count of parent=" << model->rowCount(parent); // << "display of last=" << model->data( model->index(start-1, 0, parent) ); 0477 // qDebug() << model->index(start-1, 0, parent) << model->data( model->index(start-1, 0, parent) ); 0478 Changing c; 0479 c.parent = parent; 0480 c.oldSize = model->rowCount(parent); 0481 c.last = model->data(model->index(start - 1, 0, parent)); 0482 c.next = model->data(model->index(start, 0, parent)); 0483 insert.push(c); 0484 if (pedantic) { 0485 ensureConsistent(); 0486 status.type = Status::InsertingRows; 0487 } 0488 } 0489 0490 /*! 0491 Confirm that what was said was going to happen actually did 0492 0493 \sa rowsAboutToBeInserted() 0494 */ 0495 void ModelTest::rowsInserted(const QModelIndex &parent, int start, int end) 0496 { 0497 Changing c = insert.pop(); 0498 QVERIFY(c.parent == parent); 0499 qDebug() << "rowsInserted" 0500 << "start=" << start << "end=" << end << "oldsize=" << c.oldSize << "parent=" << model->data(parent).toString() 0501 << "current rowcount of parent=" << model->rowCount(parent); 0502 0503 for (int ii = start; ii <= end; ii++) { 0504 qDebug() << "itemWasInserted:" << ii << model->data(model->index(ii, 0, parent)); 0505 } 0506 0507 QVERIFY(c.oldSize + (end - start + 1) == model->rowCount(parent)); 0508 QVERIFY(c.last == model->data(model->index(start - 1, 0, c.parent))); 0509 0510 /* 0511 if (c.next != model->data(model->index(end + 1, 0, c.parent))) { 0512 qDebug() << start << end; 0513 for (int i=0; i < model->rowCount(); ++i) 0514 qDebug() << model->index(i, 0).data().toString(); 0515 qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent)); 0516 } 0517 */ 0518 0519 QVERIFY(c.next == model->data(model->index(end + 1, 0, c.parent))); 0520 0521 if (pedantic) { 0522 QVERIFY(status.type == Status::InsertingRows); 0523 refreshStatus(); 0524 } 0525 } 0526 0527 void ModelTest::modelAboutToBeReset() 0528 { 0529 qDebug() << "@@@@@@@@@@@" 0530 << "modelAboutToBeReset"; 0531 0532 if (pedantic) { 0533 ensureConsistent(); 0534 status.type = Status::Resetting; 0535 } 0536 } 0537 0538 void ModelTest::modelReset() 0539 { 0540 qDebug() << "@@@@@@@@@@@" 0541 << "modelReset"; 0542 if (pedantic) { 0543 Q_ASSERT(status.type == Status::Resetting); 0544 refreshStatus(); 0545 } 0546 } 0547 0548 void ModelTest::layoutAboutToBeChanged() 0549 { 0550 qDebug() << "@@@@@@@@@@@" 0551 << "layoutAboutToBeChanged"; 0552 0553 if (pedantic) { 0554 ensureConsistent(); 0555 status.type = Status::ChangingLayout; 0556 } 0557 for (int i = 0; i < qBound(0, model->rowCount(), 100); ++i) { 0558 changing.append(QPersistentModelIndex(model->index(i, 0))); 0559 } 0560 } 0561 0562 void ModelTest::layoutChanged() 0563 { 0564 qDebug() << "@@@@@@@@@@@" 0565 << "layoutAboutToBeChanged"; 0566 for (int i = 0; i < changing.count(); ++i) { 0567 QPersistentModelIndex p = changing[i]; 0568 QVERIFY(p == model->index(p.row(), p.column(), p.parent())); 0569 } 0570 changing.clear(); 0571 0572 if (pedantic) { 0573 QVERIFY(status.type == Status::ChangingLayout); 0574 refreshStatus(); 0575 } 0576 } 0577 0578 void ModelTest::rowsAboutToBeMoved(const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destinationRow) 0579 { 0580 qDebug() << "rowsAboutToBeMoved" << srcParent << start << end << destParent << destinationRow; 0581 0582 for (int row = start, dr = destinationRow; row <= end; ++row, ++dr) { 0583 qDebug() << "row" << model->index(row, 0, srcParent).data() << "in " << srcParent << "will be moved to " << destParent << dr; 0584 } 0585 0586 Changing cs; 0587 cs.parent = srcParent; 0588 cs.oldSize = model->rowCount(srcParent); 0589 cs.last = model->data(model->index(start - 1, 0, srcParent)); 0590 cs.next = model->data(model->index(end + 1, 0, srcParent)); 0591 remove.push(cs); 0592 Changing cd; 0593 cd.parent = destParent; 0594 cd.oldSize = model->rowCount(destParent); 0595 cd.last = model->data(model->index(destinationRow - 1, 0, destParent)); 0596 cd.next = model->data(model->index(destinationRow, 0, destParent)); 0597 insert.push(cd); 0598 } 0599 0600 void ModelTest::rowsMoved(const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destinationRow) 0601 { 0602 qDebug() << "rowsMoved" << srcParent << start << end << destParent << destinationRow; 0603 0604 Changing cd = insert.pop(); 0605 QVERIFY(cd.parent == destParent); 0606 if (srcParent == destParent) { 0607 QVERIFY(cd.oldSize == model->rowCount(destParent)); 0608 0609 // TODO: Find out what I can assert here about last and next. 0610 // QVERIFY ( cd.last == model->data ( model->index ( destinationRow - 1, 0, cd.parent ) ) ); 0611 // QVERIFY ( cd.next == model->data ( model->index ( destinationRow + (end - start + 1), 0, cd.parent ) ) ); 0612 0613 } else { 0614 qDebug() << cd.oldSize << end << start << model->rowCount(destParent) << destParent.data() << "#########"; 0615 QVERIFY(cd.oldSize + (end - start + 1) == model->rowCount(destParent)); 0616 0617 QVERIFY(cd.last == model->data(model->index(destinationRow - 1, 0, cd.parent))); 0618 QVERIFY(cd.next == model->data(model->index(destinationRow + (end - start + 1), 0, cd.parent))); 0619 } 0620 Changing cs = remove.pop(); 0621 0622 QVERIFY(cs.parent == srcParent); 0623 if (srcParent == destParent) { 0624 QVERIFY(cs.oldSize == model->rowCount(srcParent)); 0625 } else { 0626 QVERIFY(cs.oldSize - (end - start + 1) == model->rowCount(srcParent)); 0627 0628 QVERIFY(cs.last == model->data(model->index(start - 1, 0, srcParent))); 0629 // qDebug() << cs.next << model->data ( model->index ( start, 0, srcParent ) ); 0630 QVERIFY(cs.next == model->data(model->index(start, 0, srcParent))); 0631 } 0632 } 0633 0634 /*! 0635 Store what is about to be inserted to make sure it actually happens 0636 0637 \sa rowsRemoved() 0638 */ 0639 void ModelTest::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) 0640 { 0641 qDebug() << "ratbr" << parent << start << end; 0642 for (int ii = start; ii <= end; ii++) { 0643 qDebug() << "itemwillbe removed:" << model->data(model->index(ii, 0, parent)); 0644 } 0645 0646 if (pedantic) { 0647 ensureConsistent(); 0648 status.type = Status::RemovingRows; 0649 } 0650 0651 Changing c; 0652 c.parent = parent; 0653 c.oldSize = model->rowCount(parent); 0654 c.last = model->data(model->index(start - 1, 0, parent)); 0655 c.next = model->data(model->index(end + 1, 0, parent)); 0656 remove.push(c); 0657 } 0658 0659 /*! 0660 Confirm that what was said was going to happen actually did 0661 0662 \sa rowsAboutToBeRemoved() 0663 */ 0664 void ModelTest::rowsRemoved(const QModelIndex &parent, int start, int end) 0665 { 0666 qDebug() << "rr" << parent << start << end; 0667 Changing c = remove.pop(); 0668 QVERIFY(c.parent == parent); 0669 qDebug() << (c.oldSize - (end - start + 1)) << model->rowCount(parent); 0670 QVERIFY(c.oldSize - (end - start + 1) == model->rowCount(parent)); 0671 QVERIFY(c.last == model->data(model->index(start - 1, 0, c.parent))); 0672 QVERIFY(c.next == model->data(model->index(start, 0, c.parent))); 0673 0674 if (pedantic) { 0675 Q_ASSERT(status.type == Status::RemovingRows); 0676 refreshStatus(); 0677 } 0678 } 0679 0680 void ModelTest::refreshStatus() 0681 { 0682 status.type = Status::Idle; 0683 status.nonPersistent.clear(); 0684 status.persistent.clear(); 0685 0686 persistStatus(QModelIndex()); 0687 } 0688 0689 void ModelTest::persistStatus(const QModelIndex &index) 0690 { 0691 const int rowCount = model->rowCount(index); 0692 for (int row = 0; row < rowCount; ++row) { 0693 // TODO: Test multi columns 0694 static const int column = 0; 0695 QPersistentModelIndex idx = model->index(row, column, index); 0696 status.persistent.append(idx); 0697 status.nonPersistent.append(idx); 0698 persistStatus(idx); 0699 } 0700 } 0701 0702 void ModelTest::ensureSteady() 0703 { 0704 Q_ASSERT(insert.isEmpty()); 0705 Q_ASSERT(remove.isEmpty()); 0706 Q_ASSERT(changing.isEmpty()); 0707 ensureConsistent(); 0708 } 0709 0710 void ModelTest::ensureConsistent() 0711 { 0712 Q_ASSERT(status.type == Status::Idle); 0713 0714 Q_ASSERT(status.nonPersistent.size() == status.persistent.size()); 0715 for (int i = 0; i < status.nonPersistent.size(); ++i) { 0716 Q_ASSERT(status.nonPersistent.at(i) == status.persistent.at(i)); 0717 } 0718 } 0719 0720 void ModelTest::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) 0721 { 0722 QVERIFY(topLeft.isValid()); 0723 QVERIFY(bottomRight.isValid()); 0724 QModelIndex commonParent = bottomRight.parent(); 0725 QVERIFY(topLeft.parent() == commonParent); 0726 QVERIFY(topLeft.row() <= bottomRight.row()); 0727 QVERIFY(topLeft.column() <= bottomRight.column()); 0728 int rowCount = model->rowCount(commonParent); 0729 int columnCount = model->columnCount(commonParent); 0730 QVERIFY(bottomRight.row() < rowCount); 0731 QVERIFY(bottomRight.column() < columnCount); 0732 } 0733 0734 void ModelTest::headerDataChanged(Qt::Orientation orientation, int start, int end) 0735 { 0736 QVERIFY(start >= 0); 0737 QVERIFY(end >= 0); 0738 QVERIFY(start <= end); 0739 int itemCount = orientation == Qt::Vertical ? model->rowCount() : model->columnCount(); 0740 QVERIFY(start < itemCount); 0741 QVERIFY(end < itemCount); 0742 } 0743 0744 #include "moc_modeltest.cpp"