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