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