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