Falkon Develop
Cross-platform Qt-based web browser
modeltest.cpp
Go to the documentation of this file.
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** GNU Lesser General Public License Usage
11** This file may be used under the terms of the GNU Lesser General Public
12** License version 2.1 as published by the Free Software Foundation and
13** appearing in the file LICENSE.LGPL included in the packaging of this
14** file. Please review the following information to ensure the GNU Lesser
15** General Public License version 2.1 requirements will be met:
16** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17**
18** In addition, as a special exception, Nokia gives you certain additional
19** rights. These rights are described in the Nokia Qt LGPL Exception
20** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21**
22** GNU General Public License Usage
23** Alternatively, this file may be used under the terms of the GNU General
24** Public License version 3.0 as published by the Free Software Foundation
25** and appearing in the file LICENSE.GPL included in the packaging of this
26** file. Please review the following information to ensure the GNU General
27** Public License version 3.0 requirements will be met:
28** http://www.gnu.org/copyleft/gpl.html.
29**
30** Other Usage
31** Alternatively, this file may be used in accordance with the terms and
32** conditions contained in a signed written agreement between you and Nokia.
33**
34**
35**
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42
43#include <QtGui/QtGui>
44
45#include "modeltest.h"
46
47//#include <QtTest/QtTest>
48//#undef Q_ASSERT
49//#define Q_ASSERT QVERIFY
50
51Q_DECLARE_METATYPE(QModelIndex)
52
53
56ModelTest::ModelTest(QAbstractItemModel* _model, QObject* parent) : QObject(parent), model(_model), fetchingMore(false)
57{
58 Q_ASSERT(model);
59
60 connect(model, &QAbstractItemModel::columnsAboutToBeInserted,
62 connect(model, &QAbstractItemModel::columnsAboutToBeRemoved,
64 connect(model, &QAbstractItemModel::columnsInserted,
66 connect(model, &QAbstractItemModel::columnsRemoved,
68 connect(model, &QAbstractItemModel::dataChanged,
70 connect(model, &QAbstractItemModel::headerDataChanged,
72 connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, &ModelTest::runAllTests);
73 connect(model, &QAbstractItemModel::layoutChanged, this, &ModelTest::runAllTests);
74 connect(model, &QAbstractItemModel::modelReset, this, &ModelTest::runAllTests);
75 connect(model, &QAbstractItemModel::rowsAboutToBeInserted,
77 connect(model, &QAbstractItemModel::rowsAboutToBeRemoved,
79 connect(model, &QAbstractItemModel::rowsInserted,
81 connect(model, &QAbstractItemModel::rowsRemoved,
83
84 // Special checks for inserting/removing
85 connect(model, &QAbstractItemModel::layoutAboutToBeChanged,
87 connect(model, &QAbstractItemModel::layoutChanged,
89
90 connect(model, &QAbstractItemModel::rowsAboutToBeInserted,
92 connect(model, &QAbstractItemModel::rowsAboutToBeRemoved,
94 connect(model, &QAbstractItemModel::rowsInserted,
96 connect(model, &QAbstractItemModel::rowsRemoved,
98
99 runAllTests();
100}
101
103{
104 if (fetchingMore) {
105 return;
106 }
107 nonDestructiveBasicTest();
108 rowCount();
109 columnCount();
110 hasIndex();
111 index();
112 parent();
113 data();
114}
115
120void ModelTest::nonDestructiveBasicTest()
121{
122 Q_ASSERT(model->buddy(QModelIndex()) == QModelIndex());
123 model->canFetchMore(QModelIndex());
124 Q_ASSERT(model->columnCount(QModelIndex()) >= 0);
125 Q_ASSERT(model->data(QModelIndex()) == QVariant());
126 fetchingMore = true;
127 model->fetchMore(QModelIndex());
128 fetchingMore = false;
129 Qt::ItemFlags flags = model->flags(QModelIndex());
130 Q_ASSERT(flags == Qt::ItemIsDropEnabled || flags == 0);
131 model->hasChildren(QModelIndex());
132 model->hasIndex(0, 0);
133 model->headerData(0, Qt::Horizontal);
134 model->index(0, 0);
135 model->itemData(QModelIndex());
136 QVariant cache;
137 model->match(QModelIndex(), -1, cache);
138 model->mimeTypes();
139 Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
140 Q_ASSERT(model->rowCount() >= 0);
141 QVariant variant;
142 model->setData(QModelIndex(), variant, -1);
143 model->setHeaderData(-1, Qt::Horizontal, QVariant());
144 model->setHeaderData(999999, Qt::Horizontal, QVariant());
145 QMap<int, QVariant> roles;
146 model->sibling(0, 0, QModelIndex());
147 model->span(QModelIndex());
148 model->supportedDropActions();
149}
150
156void ModelTest::rowCount()
157{
158// qDebug() << "rc";
159 // check top row
160 QModelIndex topIndex = model->index(0, 0, QModelIndex());
161 int rows = model->rowCount(topIndex);
162 Q_ASSERT(rows >= 0);
163 if (rows > 0) {
164 Q_ASSERT(model->hasChildren(topIndex) == true);
165 }
166
167 QModelIndex secondLevelIndex = model->index(0, 0, topIndex);
168 if (secondLevelIndex.isValid()) { // not the top level
169 // check a row count where parent is valid
170 rows = model->rowCount(secondLevelIndex);
171 Q_ASSERT(rows >= 0);
172 if (rows > 0) {
173 Q_ASSERT(model->hasChildren(secondLevelIndex) == true);
174 }
175 }
176
177 // The models rowCount() is tested more extensively in checkChildren(),
178 // but this catches the big mistakes
179}
180
184void ModelTest::columnCount()
185{
186 // check top row
187 QModelIndex topIndex = model->index(0, 0, QModelIndex());
188 Q_ASSERT(model->columnCount(topIndex) >= 0);
189
190 // check a column count where parent is valid
191 QModelIndex childIndex = model->index(0, 0, topIndex);
192 if (childIndex.isValid()) {
193 Q_ASSERT(model->columnCount(childIndex) >= 0);
194 }
195
196 // columnCount() is tested more extensively in checkChildren(),
197 // but this catches the big mistakes
198}
199
203void ModelTest::hasIndex()
204{
205// qDebug() << "hi";
206 // Make sure that invalid values returns an invalid index
207 Q_ASSERT(model->hasIndex(-2, -2) == false);
208 Q_ASSERT(model->hasIndex(-2, 0) == false);
209 Q_ASSERT(model->hasIndex(0, -2) == false);
210
211 int rows = model->rowCount();
212 int columns = model->columnCount();
213
214 // check out of bounds
215 Q_ASSERT(model->hasIndex(rows, columns) == false);
216 Q_ASSERT(model->hasIndex(rows + 1, columns + 1) == false);
217
218 if (rows > 0) {
219 Q_ASSERT(model->hasIndex(0, 0) == true);
220 }
221
222 // hasIndex() is tested more extensively in checkChildren(),
223 // but this catches the big mistakes
224}
225
229void ModelTest::index()
230{
231// qDebug() << "i";
232 // Make sure that invalid values returns an invalid index
233 Q_ASSERT(model->index(-2, -2) == QModelIndex());
234 Q_ASSERT(model->index(-2, 0) == QModelIndex());
235 Q_ASSERT(model->index(0, -2) == QModelIndex());
236
237 int rows = model->rowCount();
238 int columns = model->columnCount();
239
240 if (rows == 0) {
241 return;
242 }
243
244 // Catch off by one errors
245 Q_ASSERT(model->index(rows, columns) == QModelIndex());
246 Q_ASSERT(model->index(0, 0).isValid() == true);
247
248 // Make sure that the same index is *always* returned
249 QModelIndex a = model->index(0, 0);
250 QModelIndex b = model->index(0, 0);
251 Q_ASSERT(a == b);
252
253 // index() is tested more extensively in checkChildren(),
254 // but this catches the big mistakes
255}
256
260void ModelTest::parent()
261{
262// qDebug() << "p";
263 // Make sure the model wont crash and will return an invalid QModelIndex
264 // when asked for the parent of an invalid index.
265 Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
266
267 if (model->rowCount() == 0) {
268 return;
269 }
270
271 // Column 0 | Column 1 |
272 // QModelIndex() | |
273 // \- topIndex | topIndex1 |
274 // \- childIndex | childIndex1 |
275
276 // Common error test #1, make sure that a top level index has a parent
277 // that is a invalid QModelIndex.
278 QModelIndex topIndex = model->index(0, 0, QModelIndex());
279 Q_ASSERT(model->parent(topIndex) == QModelIndex());
280
281 // Common error test #2, make sure that a second level index has a parent
282 // that is the first level index.
283 if (model->rowCount(topIndex) > 0) {
284 QModelIndex childIndex = model->index(0, 0, topIndex);
285 Q_ASSERT(model->parent(childIndex) == topIndex);
286 }
287
288 // Common error test #3, the second column should NOT have the same children
289 // as the first column in a row.
290 // Usually the second column shouldn't have children.
291 QModelIndex topIndex1 = model->index(0, 1, QModelIndex());
292 if (model->rowCount(topIndex1) > 0) {
293 QModelIndex childIndex = model->index(0, 0, topIndex);
294 QModelIndex childIndex1 = model->index(0, 0, topIndex1);
295 Q_ASSERT(childIndex != childIndex1);
296 }
297
298 // Full test, walk n levels deep through the model making sure that all
299 // parent's children correctly specify their parent.
300 checkChildren(QModelIndex());
301}
302
317void ModelTest::checkChildren(const QModelIndex &parent, int currentDepth)
318{
319 // First just try walking back up the tree.
320 QModelIndex p = parent;
321 while (p.isValid()) {
322 p = p.parent();
323 }
324
325 // For models that are dynamically populated
326 if (model->canFetchMore(parent)) {
327 fetchingMore = true;
328 model->fetchMore(parent);
329 fetchingMore = false;
330 }
331
332 int rows = model->rowCount(parent);
333 int columns = model->columnCount(parent);
334
335 if (rows > 0) {
336 Q_ASSERT(model->hasChildren(parent));
337 }
338
339 // Some further testing against rows(), columns(), and hasChildren()
340 Q_ASSERT(rows >= 0);
341 Q_ASSERT(columns >= 0);
342 if (rows > 0) {
343 Q_ASSERT(model->hasChildren(parent) == true);
344 }
345
346 //qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows
347 // << "columns:" << columns << "parent column:" << parent.column();
348
349 Q_ASSERT(model->hasIndex(rows + 1, 0, parent) == false);
350 for (int r = 0; r < rows; ++r) {
351 if (model->canFetchMore(parent)) {
352 fetchingMore = true;
353 model->fetchMore(parent);
354 fetchingMore = false;
355 }
356 Q_ASSERT(model->hasIndex(r, columns + 1, parent) == false);
357 for (int c = 0; c < columns; ++c) {
358 Q_ASSERT(model->hasIndex(r, c, parent) == true);
359 QModelIndex index = model->index(r, c, parent);
360 // rowCount() and columnCount() said that it existed...
361 Q_ASSERT(index.isValid() == true);
362
363 // index() should always return the same index when called twice in a row
364 QModelIndex modifiedIndex = model->index(r, c, parent);
365 Q_ASSERT(index == modifiedIndex);
366
367 // Make sure we get the same index if we request it twice in a row
368 QModelIndex a = model->index(r, c, parent);
369 QModelIndex b = model->index(r, c, parent);
370 Q_ASSERT(a == b);
371
372 // Some basic checking on the index that is returned
373 Q_ASSERT(index.model() == model);
374 Q_ASSERT(index.row() == r);
375 Q_ASSERT(index.column() == c);
376 // While you can technically return a QVariant usually this is a sign
377 // of an bug in data() Disable if this really is ok in your model.
378 Q_ASSERT ( model->data ( index, Qt::DisplayRole ).isValid() == true );
379
380 // If the next test fails here is some somewhat useful debug you play with.
381
382 if (model->parent(index) != parent) {
383 qDebug() << r << c << currentDepth << model->data(index).toString()
384 << model->data(parent).toString();
385 qDebug() << index << parent << model->parent(index);
386// And a view that you can even use to show the model.
387// QTreeView view;
388// view.setModel(model);
389// view.show();
390 return;
391 }
392
393 // Check that we can get back our real parent.
394// qDebug() << model->parent ( index ) << parent ;
395 Q_ASSERT(model->parent(index) == parent);
396
397 // recursively go down the children
398 if (model->hasChildren(index) && currentDepth < 10) {
399 //qDebug() << r << c << "has children" << model->rowCount(index);
400 checkChildren(index, ++currentDepth);
401 }/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/
402
403 // make sure that after testing the children that the index doesn't change.
404 QModelIndex newerIndex = model->index(r, c, parent);
405 Q_ASSERT(index == newerIndex);
406 }
407 }
408}
409
413void ModelTest::data()
414{
415 // Invalid index should return an invalid qvariant
416 Q_ASSERT(!model->data(QModelIndex()).isValid());
417
418 if (model->rowCount() == 0) {
419 return;
420 }
421
422 // A valid index should have a valid QVariant data
423 Q_ASSERT(model->index(0, 0).isValid());
424
425 // shouldn't be able to set data on an invalid index
426 Q_ASSERT(model->setData(QModelIndex(), QLatin1String("foo"), Qt::DisplayRole) == false);
427
428 // General Purpose roles that should return a QString
429 QVariant variant = model->data(model->index(0, 0), Qt::ToolTipRole);
430 if (variant.isValid()) {
431 Q_ASSERT(variant.canConvert<QString>());
432 }
433 variant = model->data(model->index(0, 0), Qt::StatusTipRole);
434 if (variant.isValid()) {
435 Q_ASSERT(variant.canConvert<QString>());
436 }
437 variant = model->data(model->index(0, 0), Qt::WhatsThisRole);
438 if (variant.isValid()) {
439 Q_ASSERT(variant.canConvert<QString>());
440 }
441
442 // General Purpose roles that should return a QSize
443 variant = model->data(model->index(0, 0), Qt::SizeHintRole);
444 if (variant.isValid()) {
445 Q_ASSERT(variant.canConvert<QSize>());
446 }
447
448 // General Purpose roles that should return a QFont
449 QVariant fontVariant = model->data(model->index(0, 0), Qt::FontRole);
450 if (fontVariant.isValid()) {
451 Q_ASSERT(fontVariant.canConvert<QFont>());
452 }
453
454 // Check that the alignment is one we know about
455 QVariant textAlignmentVariant = model->data(model->index(0, 0), Qt::TextAlignmentRole);
456 if (textAlignmentVariant.isValid()) {
457 int alignment = textAlignmentVariant.toInt();
458 Q_ASSERT(alignment == int(alignment & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)));
459 }
460
461 // General Purpose roles that should return a QColor
462 QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundRole);
463 if (colorVariant.isValid()) {
464 Q_ASSERT(colorVariant.canConvert<QColor>());
465 }
466
467 colorVariant = model->data(model->index(0, 0), Qt::ForegroundRole);
468 if (colorVariant.isValid()) {
469 Q_ASSERT(colorVariant.canConvert<QColor>());
470 }
471
472 // Check that the "check state" is one we know about.
473 QVariant checkStateVariant = model->data(model->index(0, 0), Qt::CheckStateRole);
474 if (checkStateVariant.isValid()) {
475 int state = checkStateVariant.toInt();
476 Q_ASSERT(state == Qt::Unchecked ||
477 state == Qt::PartiallyChecked ||
478 state == Qt::Checked);
479 }
480}
481
487void ModelTest::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
488{
489 Q_UNUSED(end);
490// qDebug() << "rowsAboutToBeInserted" << "start=" << start << "end=" << end << "parent=" << model->data ( parent ).toString()
491// << "current count of parent=" << model->rowCount ( parent ); // << "display of last=" << model->data( model->index(start-1, 0, parent) );
492// qDebug() << model->index(start-1, 0, parent) << model->data( model->index(start-1, 0, parent) );
493 Changing c;
494 c.parent = parent;
495 c.oldSize = model->rowCount(parent);
496 c.last = model->data(model->index(start - 1, 0, parent));
497 c.next = model->data(model->index(start, 0, parent));
498 insert.push(c);
499}
500
506void ModelTest::rowsInserted(const QModelIndex &parent, int start, int end)
507{
508 Changing c = insert.pop();
509 Q_ASSERT(c.parent == parent);
510// qDebug() << "rowsInserted" << "start=" << start << "end=" << end << "oldsize=" << c.oldSize
511// << "parent=" << model->data ( parent ).toString() << "current rowcount of parent=" << model->rowCount ( parent );
512
513// for (int ii=start; ii <= end; ii++)
514// {
515// qDebug() << "itemWasInserted:" << ii << model->data ( model->index ( ii, 0, parent ));
516// }
517// qDebug();
518
519 Q_ASSERT(c.oldSize + (end - start + 1) == model->rowCount(parent));
520 Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
521
522 if (c.next != model->data(model->index(end + 1, 0, c.parent))) {
523 qDebug() << start << end;
524 for (int i = 0; i < model->rowCount(); ++i) {
525 qDebug() << model->index(i, 0).data().toString();
526 }
527 qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent));
528 }
529
530 Q_ASSERT(c.next == model->data(model->index(end + 1, 0, c.parent)));
531}
532
534{
535 for (int i = 0; i < qBound(0, model->rowCount(), 100); ++i) {
536 changing.append(QPersistentModelIndex(model->index(i, 0)));
537 }
538}
539
541{
542 for (int i = 0; i < changing.count(); ++i) {
543 QPersistentModelIndex p = changing[i];
544 Q_ASSERT(p == model->index(p.row(), p.column(), p.parent()));
545 }
546 changing.clear();
547}
548
554void ModelTest::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
555{
556 qDebug() << "ratbr" << parent << start << end;
557 Changing c;
558 c.parent = parent;
559 c.oldSize = model->rowCount(parent);
560 c.last = model->data(model->index(start - 1, 0, parent));
561 c.next = model->data(model->index(end + 1, 0, parent));
562 remove.push(c);
563}
564
570void ModelTest::rowsRemoved(const QModelIndex &parent, int start, int end)
571{
572 qDebug() << "rr" << parent << start << end;
573 Changing c = remove.pop();
574 Q_ASSERT(c.parent == parent);
575 Q_ASSERT(c.oldSize - (end - start + 1) == model->rowCount(parent));
576 Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
577 Q_ASSERT(c.next == model->data(model->index(start, 0, c.parent)));
578}
579
580
void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
Definition: modeltest.cpp:487
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
Definition: modeltest.cpp:554
void layoutChanged()
Definition: modeltest.cpp:540
void layoutAboutToBeChanged()
Definition: modeltest.cpp:533
void runAllTests()
Definition: modeltest.cpp:102
void rowsRemoved(const QModelIndex &parent, int start, int end)
Definition: modeltest.cpp:570
void rowsInserted(const QModelIndex &parent, int start, int end)
Definition: modeltest.cpp:506
Q_DECLARE_METATYPE(FlashCookie)
i
Definition: i18n.py:23
State state