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