1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33 
34 #include "modeltest.h"
35 
36 #include <QtCore>
37 #include <QtTest>
38 
39 /*!
40     Connect to all of the models signals.  Whenever anything happens recheck everything.
41 */
ModelTest(QAbstractItemModel * _model,QObject * parent)42 ModelTest::ModelTest ( QAbstractItemModel *_model, QObject *parent ) : QObject ( parent ), model ( _model ), fetchingMore ( false )
43 {
44     if (!model)
45         qFatal("%s: model must not be null", Q_FUNC_INFO);
46 
47     connect(model, SIGNAL(columnsAboutToBeInserted(QModelIndex,int,int)),
48             this, SLOT(runAllTests()) );
49     connect(model, SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
50             this, SLOT(runAllTests()) );
51     connect(model, SIGNAL(columnsInserted(QModelIndex,int,int)),
52             this, SLOT(runAllTests()) );
53     connect(model, SIGNAL(columnsRemoved(QModelIndex,int,int)),
54             this, SLOT(runAllTests()) );
55     connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
56             this, SLOT(runAllTests()) );
57     connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
58             this, SLOT(runAllTests()) );
59     connect(model, SIGNAL(layoutAboutToBeChanged()), this, SLOT(runAllTests()) );
60     connect(model, SIGNAL(layoutChanged()), this, SLOT(runAllTests()) );
61     connect(model, SIGNAL(modelReset()), this, SLOT(runAllTests()) );
62     connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
63             this, SLOT(runAllTests()) );
64     connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
65             this, SLOT(runAllTests()) );
66     connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
67             this, SLOT(runAllTests()) );
68     connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
69             this, SLOT(runAllTests()) );
70 
71     // Special checks for changes
72     connect(model, SIGNAL(layoutAboutToBeChanged()),
73             this, SLOT(layoutAboutToBeChanged()) );
74     connect(model, SIGNAL(layoutChanged()),
75             this, SLOT(layoutChanged()) );
76 
77     connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
78             this, SLOT(rowsAboutToBeInserted(QModelIndex,int,int)) );
79     connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
80             this, SLOT(rowsAboutToBeRemoved(QModelIndex,int,int)) );
81     connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)),
82             this, SLOT(rowsInserted(QModelIndex,int,int)) );
83     connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)),
84             this, SLOT(rowsRemoved(QModelIndex,int,int)) );
85     connect(model, SIGNAL (rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)),
86             this, SLOT (rowsAboutToBeMoved(QModelIndex,int,int,QModelIndex,int)) );
87     connect(model, SIGNAL (rowsMoved(QModelIndex,int,int,QModelIndex,int)),
88             this, SLOT (rowsMoved(QModelIndex,int,int,QModelIndex,int)) );
89     connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
90             this, SLOT(dataChanged(QModelIndex,QModelIndex)) );
91     connect(model, SIGNAL(headerDataChanged(Qt::Orientation,int,int)),
92             this, SLOT(headerDataChanged(Qt::Orientation,int,int)) );
93 
94     runAllTests();
95 }
96 
runAllTests()97 void ModelTest::runAllTests()
98 {
99     if ( fetchingMore )
100         return;
101     nonDestructiveBasicTest();
102     rowCount();
103     columnCount();
104     hasIndex();
105     index();
106     parent();
107     data();
108 }
109 
110 /*!
111     nonDestructiveBasicTest tries to call a number of the basic functions (not all)
112     to make sure the model doesn't outright segfault, testing the functions that makes sense.
113 */
nonDestructiveBasicTest()114 void ModelTest::nonDestructiveBasicTest()
115 {
116     QVERIFY( model->buddy ( QModelIndex() ) == QModelIndex() );
117     model->canFetchMore ( QModelIndex() );
118     QVERIFY( model->columnCount ( QModelIndex() ) >= 0 );
119     QVERIFY( model->data ( QModelIndex() ) == QVariant() );
120     fetchingMore = true;
121     model->fetchMore ( QModelIndex() );
122     fetchingMore = false;
123     Qt::ItemFlags flags = model->flags ( QModelIndex() );
124     QVERIFY( flags == Qt::ItemIsDropEnabled || flags == 0 );
125     model->hasChildren ( QModelIndex() );
126     model->hasIndex ( 0, 0 );
127     model->headerData ( 0, Qt::Horizontal );
128     model->index ( 0, 0 );
129     model->itemData ( QModelIndex() );
130     QVariant cache;
131     model->match ( QModelIndex(), -1, cache );
132     model->mimeTypes();
133     QVERIFY( model->parent ( QModelIndex() ) == QModelIndex() );
134     QVERIFY( model->rowCount() >= 0 );
135     QVariant variant;
136     model->setData ( QModelIndex(), variant, -1 );
137     model->setHeaderData ( -1, Qt::Horizontal, QVariant() );
138     model->setHeaderData ( 999999, Qt::Horizontal, QVariant() );
139     QMap<int, QVariant> roles;
140     model->sibling ( 0, 0, QModelIndex() );
141     model->span ( QModelIndex() );
142     model->supportedDropActions();
143 }
144 
145 /*!
146     Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren()
147 
148     Models that are dynamically populated are not as fully tested here.
149  */
rowCount()150 void ModelTest::rowCount()
151 {
152 //     qDebug() << "rc";
153     // check top row
154     QModelIndex topIndex = model->index ( 0, 0, QModelIndex() );
155     int rows = model->rowCount ( topIndex );
156     QVERIFY( rows >= 0 );
157     if ( rows > 0 )
158         QVERIFY( model->hasChildren ( topIndex ) );
159 
160     QModelIndex secondLevelIndex = model->index ( 0, 0, topIndex );
161     if ( secondLevelIndex.isValid() ) { // not the top level
162         // check a row count where parent is valid
163         rows = model->rowCount ( secondLevelIndex );
164         QVERIFY( rows >= 0 );
165         if ( rows > 0 )
166             QVERIFY( model->hasChildren ( secondLevelIndex ) );
167     }
168 
169     // The models rowCount() is tested more extensively in checkChildren(),
170     // but this catches the big mistakes
171 }
172 
173 /*!
174     Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren()
175  */
columnCount()176 void ModelTest::columnCount()
177 {
178     // check top row
179     QModelIndex topIndex = model->index ( 0, 0, QModelIndex() );
180     QVERIFY( model->columnCount ( topIndex ) >= 0 );
181 
182     // check a column count where parent is valid
183     QModelIndex childIndex = model->index ( 0, 0, topIndex );
184     if ( childIndex.isValid() )
185         QVERIFY( model->columnCount ( childIndex ) >= 0 );
186 
187     // columnCount() is tested more extensively in checkChildren(),
188     // but this catches the big mistakes
189 }
190 
191 /*!
192     Tests model's implementation of QAbstractItemModel::hasIndex()
193  */
hasIndex()194 void ModelTest::hasIndex()
195 {
196 //     qDebug() << "hi";
197     // Make sure that invalid values returns an invalid index
198     QVERIFY( !model->hasIndex ( -2, -2 ) );
199     QVERIFY( !model->hasIndex ( -2, 0 ) );
200     QVERIFY( !model->hasIndex ( 0, -2 ) );
201 
202     int rows = model->rowCount();
203     int columns = model->columnCount();
204 
205     // check out of bounds
206     QVERIFY( !model->hasIndex ( rows, columns ) );
207     QVERIFY( !model->hasIndex ( rows + 1, columns + 1 ) );
208 
209     if ( rows > 0 )
210         QVERIFY( model->hasIndex ( 0, 0 ) );
211 
212     // hasIndex() is tested more extensively in checkChildren(),
213     // but this catches the big mistakes
214 }
215 
216 /*!
217     Tests model's implementation of QAbstractItemModel::index()
218  */
index()219 void ModelTest::index()
220 {
221 //     qDebug() << "i";
222     // Make sure that invalid values returns an invalid index
223     QVERIFY( model->index ( -2, -2 ) == QModelIndex() );
224     QVERIFY( model->index ( -2, 0 ) == QModelIndex() );
225     QVERIFY( model->index ( 0, -2 ) == QModelIndex() );
226 
227     int rows = model->rowCount();
228     int columns = model->columnCount();
229 
230     if ( rows == 0 )
231         return;
232 
233     // Catch off by one errors
234     QVERIFY( model->index ( rows, columns ) == QModelIndex() );
235     QVERIFY( model->index ( 0, 0 ).isValid() );
236 
237     // Make sure that the same index is *always* returned
238     QModelIndex a = model->index ( 0, 0 );
239     QModelIndex b = model->index ( 0, 0 );
240     QVERIFY( a == b );
241 
242     // index() is tested more extensively in checkChildren(),
243     // but this catches the big mistakes
244 }
245 
246 /*!
247     Tests model's implementation of QAbstractItemModel::parent()
248  */
parent()249 void ModelTest::parent()
250 {
251 //     qDebug() << "p";
252     // Make sure the model won't crash and will return an invalid QModelIndex
253     // when asked for the parent of an invalid index.
254     QVERIFY( model->parent ( QModelIndex() ) == QModelIndex() );
255 
256     if ( model->rowCount() == 0 )
257         return;
258 
259     // Column 0                | Column 1    |
260     // QModelIndex()           |             |
261     //    \- topIndex          | topIndex1   |
262     //         \- childIndex   | childIndex1 |
263 
264     // Common error test #1, make sure that a top level index has a parent
265     // that is a invalid QModelIndex.
266     QModelIndex topIndex = model->index ( 0, 0, QModelIndex() );
267     QVERIFY( model->parent ( topIndex ) == QModelIndex() );
268 
269     // Common error test #2, make sure that a second level index has a parent
270     // that is the first level index.
271     if ( model->rowCount ( topIndex ) > 0 ) {
272         QModelIndex childIndex = model->index ( 0, 0, topIndex );
273         QVERIFY( model->parent ( childIndex ) == topIndex );
274     }
275 
276     // Common error test #3, the second column should NOT have the same children
277     // as the first column in a row.
278     // Usually the second column shouldn't have children.
279     QModelIndex topIndex1 = model->index ( 0, 1, QModelIndex() );
280     if ( model->rowCount ( topIndex1 ) > 0 ) {
281         QModelIndex childIndex = model->index ( 0, 0, topIndex );
282         QModelIndex childIndex1 = model->index ( 0, 0, topIndex1 );
283         QVERIFY( childIndex != childIndex1 );
284     }
285 
286     // Full test, walk n levels deep through the model making sure that all
287     // parent's children correctly specify their parent.
288     checkChildren ( QModelIndex() );
289 }
290 
291 /*!
292     Called from the parent() test.
293 
294     A model that returns an index of parent X should also return X when asking
295     for the parent of the index.
296 
297     This recursive function does pretty extensive testing on the whole model in an
298     effort to catch edge cases.
299 
300     This function assumes that rowCount(), columnCount() and index() already work.
301     If they have a bug it will point it out, but the above tests should have already
302     found the basic bugs because it is easier to figure out the problem in
303     those tests then this one.
304  */
checkChildren(const QModelIndex & parent,int currentDepth)305 void ModelTest::checkChildren ( const QModelIndex &parent, int currentDepth )
306 {
307     // First just try walking back up the tree.
308     QModelIndex p = parent;
309     while ( p.isValid() )
310         p = p.parent();
311 
312     // For models that are dynamically populated
313     if ( model->canFetchMore ( parent ) ) {
314         fetchingMore = true;
315         model->fetchMore ( parent );
316         fetchingMore = false;
317     }
318 
319     int rows = model->rowCount ( parent );
320     int columns = model->columnCount ( parent );
321 
322     if ( rows > 0 )
323         QVERIFY( model->hasChildren ( parent ) );
324 
325     // Some further testing against rows(), columns(), and hasChildren()
326     QVERIFY( rows >= 0 );
327     QVERIFY( columns >= 0 );
328     if ( rows > 0 )
329         QVERIFY( model->hasChildren ( parent ) );
330 
331     //qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows
332     //         << "columns:" << columns << "parent column:" << parent.column();
333 
334     const QModelIndex topLeftChild = model->index( 0, 0, parent );
335 
336     QVERIFY( !model->hasIndex ( rows + 1, 0, parent ) );
337     for ( int r = 0; r < rows; ++r ) {
338         if ( model->canFetchMore ( parent ) ) {
339             fetchingMore = true;
340             model->fetchMore ( parent );
341             fetchingMore = false;
342         }
343         QVERIFY( !model->hasIndex ( r, columns + 1, parent ) );
344         for ( int c = 0; c < columns; ++c ) {
345             QVERIFY( model->hasIndex ( r, c, parent ) );
346             QModelIndex index = model->index ( r, c, parent );
347             // rowCount() and columnCount() said that it existed...
348             QVERIFY( index.isValid() );
349 
350             // index() should always return the same index when called twice in a row
351             QModelIndex modifiedIndex = model->index ( r, c, parent );
352             QVERIFY( index == modifiedIndex );
353 
354             // Make sure we get the same index if we request it twice in a row
355             QModelIndex a = model->index ( r, c, parent );
356             QModelIndex b = model->index ( r, c, parent );
357             QVERIFY( a == b );
358 
359             {
360                 const QModelIndex sibling = model->sibling( r, c, topLeftChild );
361                 QVERIFY( index == sibling );
362             }
363             {
364                 const QModelIndex sibling = topLeftChild.sibling( r, c );
365                 QVERIFY( index == sibling );
366             }
367 
368             // Some basic checking on the index that is returned
369             QVERIFY( index.model() == model );
370             QCOMPARE( index.row(), r );
371             QCOMPARE( index.column(), c );
372             // While you can technically return a QVariant usually this is a sign
373             // of a bug in data().  Disable if this really is ok in your model.
374 //            QVERIFY( model->data ( index, Qt::DisplayRole ).isValid() );
375 
376             // If the next test fails here is some somewhat useful debug you play with.
377 
378             if (model->parent(index) != parent) {
379                 qDebug() << r << c << currentDepth << model->data(index).toString()
380                          << model->data(parent).toString();
381                 qDebug() << index << parent << model->parent(index);
382 //                 And a view that you can even use to show the model.
383 //                 QTreeView view;
384 //                 view.setModel(model);
385 //                 view.show();
386             }
387 
388             // Check that we can get back our real parent.
389             QCOMPARE( model->parent ( index ), parent );
390 
391             // recursively go down the children
392             if ( model->hasChildren ( index ) && currentDepth < 10 ) {
393                 //qDebug() << r << c << "has children" << model->rowCount(index);
394                 checkChildren ( index, ++currentDepth );
395             }/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/
396 
397             // make sure that after testing the children that the index doesn't change.
398             QModelIndex newerIndex = model->index ( r, c, parent );
399             QVERIFY( index == newerIndex );
400         }
401     }
402 }
403 
404 /*!
405     Tests model's implementation of QAbstractItemModel::data()
406  */
data()407 void ModelTest::data()
408 {
409     // Invalid index should return an invalid qvariant
410     QVERIFY( !model->data ( QModelIndex() ).isValid() );
411 
412     if ( model->rowCount() == 0 )
413         return;
414 
415     // A valid index should have a valid QVariant data
416     QVERIFY( model->index ( 0, 0 ).isValid() );
417 
418     // shouldn't be able to set data on an invalid index
419     QVERIFY( !model->setData ( QModelIndex(), QLatin1String ( "foo" ), Qt::DisplayRole ) );
420 
421     // General Purpose roles that should return a QString
422     QVariant variant = model->data ( model->index ( 0, 0 ), Qt::ToolTipRole );
423     if ( variant.isValid() ) {
424         QVERIFY( variant.canConvert<QString>() );
425     }
426     variant = model->data ( model->index ( 0, 0 ), Qt::StatusTipRole );
427     if ( variant.isValid() ) {
428         QVERIFY( variant.canConvert<QString>() );
429     }
430     variant = model->data ( model->index ( 0, 0 ), Qt::WhatsThisRole );
431     if ( variant.isValid() ) {
432         QVERIFY( variant.canConvert<QString>() );
433     }
434 
435     // General Purpose roles that should return a QSize
436     variant = model->data ( model->index ( 0, 0 ), Qt::SizeHintRole );
437     if ( variant.isValid() ) {
438         QVERIFY( variant.canConvert<QSize>() );
439     }
440 
441     // General Purpose roles that should return a QFont
442     QVariant fontVariant = model->data ( model->index ( 0, 0 ), Qt::FontRole );
443     if ( fontVariant.isValid() ) {
444         QVERIFY( fontVariant.canConvert<QFont>() );
445     }
446 
447     // Check that the alignment is one we know about
448     QVariant textAlignmentVariant = model->data ( model->index ( 0, 0 ), Qt::TextAlignmentRole );
449     if ( textAlignmentVariant.isValid() ) {
450         int alignment = textAlignmentVariant.toInt();
451         QCOMPARE( alignment, static_cast<int>( alignment & ( Qt::AlignHorizontal_Mask
452                                                            | Qt::AlignVertical_Mask ) ) );
453     }
454 
455     // General Purpose roles that should return a QColor
456     QVariant colorVariant = model->data ( model->index ( 0, 0 ), Qt::BackgroundColorRole );
457     if ( colorVariant.isValid() ) {
458         QVERIFY( colorVariant.canConvert<QColor>() );
459     }
460 
461     colorVariant = model->data ( model->index ( 0, 0 ), Qt::TextColorRole );
462     if ( colorVariant.isValid() ) {
463         QVERIFY( colorVariant.canConvert<QColor>() );
464     }
465 
466     // Check that the "check state" is one we know about.
467     QVariant checkStateVariant = model->data ( model->index ( 0, 0 ), Qt::CheckStateRole );
468     if ( checkStateVariant.isValid() ) {
469         int state = checkStateVariant.toInt();
470         QVERIFY( state == Qt::Unchecked ||
471                  state == Qt::PartiallyChecked ||
472                  state == Qt::Checked );
473     }
474 }
475 
476 /*!
477     Store what is about to be inserted to make sure it actually happens
478 
479     \sa rowsInserted()
480  */
rowsAboutToBeInserted(const QModelIndex & parent,int start,int)481 void ModelTest::rowsAboutToBeInserted ( const QModelIndex &parent, int start, int /* end */)
482 {
483 //     Q_UNUSED(end);
484 //    qDebug() << "rowsAboutToBeInserted" << "start=" << start << "end=" << end << "parent=" << model->data ( parent ).toString()
485 //    << "current count of parent=" << model->rowCount ( parent ); // << "display of last=" << model->data( model->index(start-1, 0, parent) );
486 //     qDebug() << model->index(start-1, 0, parent) << model->data( model->index(start-1, 0, parent) );
487     Changing c;
488     c.parent = parent;
489     c.oldSize = model->rowCount ( parent );
490     c.last = model->data ( model->index ( start - 1, 0, parent ) );
491     c.next = model->data ( model->index ( start, 0, parent ) );
492     insert.push ( c );
493 }
494 
495 /*!
496     Confirm that what was said was going to happen actually did
497 
498     \sa rowsAboutToBeInserted()
499  */
rowsInserted(const QModelIndex & parent,int start,int end)500 void ModelTest::rowsInserted ( const QModelIndex & parent, int start, int end )
501 {
502     Changing c = insert.pop();
503     QVERIFY( c.parent == parent );
504 //    qDebug() << "rowsInserted"  << "start=" << start << "end=" << end << "oldsize=" << c.oldSize
505 //    << "parent=" << model->data ( parent ).toString() << "current rowcount of parent=" << model->rowCount ( parent );
506 
507 //    for (int ii=start; ii <= end; ii++)
508 //    {
509 //      qDebug() << "itemWasInserted:" << ii << model->data ( model->index ( ii, 0, parent ));
510 //    }
511 //    qDebug();
512 
513     QVERIFY( c.oldSize + ( end - start + 1 ) == model->rowCount ( parent ) );
514     QVERIFY( c.last == model->data ( model->index ( start - 1, 0, c.parent ) ) );
515 
516     if (c.next != model->data(model->index(end + 1, 0, c.parent))) {
517         qDebug() << start << end;
518         for (int i=0; i < model->rowCount(); ++i)
519             qDebug() << model->index(i, 0).data().toString();
520         qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent));
521     }
522 
523     QVERIFY( c.next == model->data ( model->index ( end + 1, 0, c.parent ) ) );
524 }
525 
layoutAboutToBeChanged()526 void ModelTest::layoutAboutToBeChanged()
527 {
528     for ( int i = 0; i < qBound ( 0, model->rowCount(), 100 ); ++i )
529         changing.append ( QPersistentModelIndex ( model->index ( i, 0 ) ) );
530 }
531 
layoutChanged()532 void ModelTest::layoutChanged()
533 {
534     for ( int i = 0; i < changing.count(); ++i ) {
535         QPersistentModelIndex p = changing[i];
536         QVERIFY( p == model->index ( p.row(), p.column(), p.parent() ) );
537     }
538     changing.clear();
539 }
540 
541 /*!
542     Store what is about to be inserted to make sure it actually happens
543 
544     \sa rowsRemoved()
545  */
rowsAboutToBeRemoved(const QModelIndex & parent,int start,int end)546 void ModelTest::rowsAboutToBeRemoved ( const QModelIndex &parent, int start, int end )
547 {
548 //qDebug() << "ratbr" << parent << start << end;
549     Changing c;
550     c.parent = parent;
551     c.oldSize = model->rowCount ( parent );
552     c.last = model->data ( model->index ( start - 1, 0, parent ) );
553     c.next = model->data ( model->index ( end + 1, 0, parent ) );
554     remove.push ( c );
555 }
556 
557 /*!
558     Confirm that what was said was going to happen actually did
559 
560     \sa rowsAboutToBeRemoved()
561  */
rowsRemoved(const QModelIndex & parent,int start,int end)562 void ModelTest::rowsRemoved ( const QModelIndex & parent, int start, int end )
563 {
564 //  qDebug() << "rr" << parent << start << end;
565     Changing c = remove.pop();
566     QVERIFY( c.parent == parent );
567     QVERIFY( c.oldSize - ( end - start + 1 ) == model->rowCount ( parent ) );
568     QVERIFY( c.last == model->data ( model->index ( start - 1, 0, c.parent ) ) );
569     QVERIFY( c.next == model->data ( model->index ( start, 0, c.parent ) ) );
570 }
571 
dataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)572 void ModelTest::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
573 {
574     QVERIFY(topLeft.isValid());
575     QVERIFY(bottomRight.isValid());
576     QModelIndex commonParent = bottomRight.parent();
577     QVERIFY(topLeft.parent() == commonParent);
578     QVERIFY(topLeft.row() <= bottomRight.row());
579     QVERIFY(topLeft.column() <= bottomRight.column());
580     int rowCount = model->rowCount(commonParent);
581     int columnCount = model->columnCount(commonParent);
582     QVERIFY(bottomRight.row() < rowCount);
583     QVERIFY(bottomRight.column() < columnCount);
584 }
585 
headerDataChanged(Qt::Orientation orientation,int start,int end)586 void ModelTest::headerDataChanged(Qt::Orientation orientation, int start, int end)
587 {
588     QVERIFY(start >= 0);
589     QVERIFY(end >= 0);
590     QVERIFY(start <= end);
591     int itemCount = orientation == Qt::Vertical ? model->rowCount() : model->columnCount();
592     QVERIFY(start < itemCount);
593     QVERIFY(end < itemCount);
594 }
595 
rowsAboutToBeMoved(const QModelIndex & srcParent,int start,int end,const QModelIndex & destParent,int destinationRow)596 void ModelTest::rowsAboutToBeMoved( const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destinationRow )
597 {
598     Changing cs;
599     cs.parent = srcParent;
600     cs.oldSize = model->rowCount ( srcParent );
601     cs.last = model->data ( model->index ( start - 1, 0, srcParent ) );
602     cs.next = model->data ( model->index ( end + 1, 0, srcParent ) );
603     remove.push ( cs );
604     Changing cd;
605     cd.parent = destParent;
606     cd.oldSize = model->rowCount ( destParent );
607     cd.last = model->data ( model->index ( destinationRow - 1, 0, destParent ) );
608     cd.next = model->data ( model->index ( destinationRow, 0, destParent ) );
609     insert.push ( cd );
610 }
611 
rowsMoved(const QModelIndex & srcParent,int start,int end,const QModelIndex & destParent,int destinationRow)612 void ModelTest::rowsMoved( const QModelIndex &srcParent, int start, int end, const QModelIndex &destParent, int destinationRow )
613 {
614     Changing cd = insert.pop();
615     QVERIFY ( cd.parent == destParent );
616     if (srcParent == destParent) {
617         QVERIFY ( cd.oldSize == model->rowCount ( destParent ) );
618 
619         // TODO: Find out what I can assert here about last and next.
620         // Q_ASSERT ( cd.last == model->data ( model->index ( destinationRow - 1, 0, cd.parent ) ) );
621         // Q_ASSERT ( cd.next == model->data ( model->index ( destinationRow + (end - start + 1), 0, cd.parent ) ) );
622     }
623     else {
624         QVERIFY ( cd.oldSize + ( end - start + 1 ) == model->rowCount ( destParent ) );
625 
626         QVERIFY ( cd.last == model->data ( model->index ( destinationRow - 1, 0, cd.parent ) ) );
627         QVERIFY ( cd.next == model->data ( model->index ( destinationRow + (end - start + 1), 0, cd.parent ) ) );
628     }
629 
630     Changing cs = remove.pop();
631     QVERIFY ( cs.parent == srcParent );
632     if (srcParent == destParent) {
633         QVERIFY ( cs.oldSize == model->rowCount ( srcParent ) );
634     }
635     else {
636         QVERIFY ( cs.oldSize - ( end - start + 1 ) == model->rowCount ( srcParent ) );
637 
638         QVERIFY ( cs.last == model->data ( model->index ( start - 1, 0, srcParent ) ) );
639         QVERIFY ( cs.next == model->data ( model->index ( start, 0, srcParent ) ) );
640     }
641 }
642