[KLF Application][KLF Tools][KLF Backend][KLF Home]
KLatexFormula Project
modeltest.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2007 Trolltech ASA. All rights reserved.
4 **
5 ** This file is part of the Qt Concurrent project on Trolltech Labs.
6 **
7 ** This file may be used under the terms of the GNU General Public
8 ** License version 2.0 as published by the Free Software Foundation
9 ** and appearing in the file LICENSE.GPL included in the packaging of
10 ** this file. Please review the following information to ensure GNU
11 ** General Public Licensing requirements will be met:
12 ** http://www.trolltech.com/products/qt/opensource.html
13 **
14 ** If you are unsure which license is appropriate for your use, please
15 ** review the following information:
16 ** http://www.trolltech.com/products/qt/licensing.html or contact the
17 ** sales department at sales@trolltech.com.
18 **
19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 **
22 ****************************************************************************/
23 
24 #ifdef KLF_DEBUG_USE_MODELTEST
25 
26 #include <QtGui/QtGui>
27 
28 #include "modeltest.h"
29 
31 
32 
35 ModelTest::ModelTest(QAbstractItemModel *_model, QObject *parent) : QObject(parent), model(_model), fetchingMore(false)
36 {
37  Q_ASSERT(model);
38 
39  connect(model, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)),
40  this, SLOT(runAllTests()));
41  connect(model, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)),
42  this, SLOT(runAllTests()));
43  connect(model, SIGNAL(columnsInserted(const QModelIndex &, int, int)),
44  this, SLOT(runAllTests()));
45  connect(model, SIGNAL(columnsRemoved(const QModelIndex &, int, int)),
46  this, SLOT(runAllTests()));
47  connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
48  this, SLOT(runAllTests()));
49  connect(model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)),
50  this, SLOT(runAllTests()));
51  connect(model, SIGNAL(layoutAboutToBeChanged ()), this, SLOT(runAllTests()));
52  connect(model, SIGNAL(layoutChanged ()), this, SLOT(runAllTests()));
53  connect(model, SIGNAL(modelReset ()), this, SLOT(runAllTests()));
54  connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
55  this, SLOT(runAllTests()));
56  connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
57  this, SLOT(runAllTests()));
58  connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
59  this, SLOT(runAllTests()));
60  connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
61  this, SLOT(runAllTests()));
62 
63  // Special checks for inserting/removing
64  connect(model, SIGNAL(layoutAboutToBeChanged()),
65  this, SLOT(layoutAboutToBeChanged()));
66  connect(model, SIGNAL(layoutChanged()),
67  this, SLOT(layoutChanged()));
68 
69  connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
70  this, SLOT(rowsAboutToBeInserted(const QModelIndex &, int, int)));
71  connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
72  this, SLOT(rowsAboutToBeRemoved(const QModelIndex &, int, int)));
73  connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
74  this, SLOT(rowsInserted(const QModelIndex &, int, int)));
75  connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
76  this, SLOT(rowsRemoved(const QModelIndex &, int, int)));
77 
78  runAllTests();
79 }
80 
81 void ModelTest::runAllTests()
82 {
83  if (fetchingMore)
84  return;
85  nonDestructiveBasicTest();
86  rowCount();
87  columnCount();
88  hasIndex();
89  index();
90  parent();
91  data();
92 }
93 
98 void ModelTest::nonDestructiveBasicTest()
99 {
100  Q_ASSERT(model->buddy(QModelIndex()) == QModelIndex());
101  model->canFetchMore(QModelIndex());
102  Q_ASSERT(model->columnCount(QModelIndex()) >= 0);
103  Q_ASSERT(model->data(QModelIndex()) == QVariant());
104  fetchingMore = true;
105  model->fetchMore(QModelIndex());
106  fetchingMore = false;
107  Qt::ItemFlags flags = model->flags(QModelIndex());
108  Q_ASSERT(flags == Qt::ItemIsDropEnabled || flags == 0);
109  model->hasChildren(QModelIndex());
110  model->hasIndex(0, 0);
111  model->headerData(0, Qt::Horizontal);
112  model->index(0, 0);
113  Q_ASSERT(model->index(-1, -1) == QModelIndex());
114  model->itemData(QModelIndex());
115  QVariant cache;
116  model->match(QModelIndex(), -1, cache);
117  model->mimeTypes();
118  Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
119  Q_ASSERT(model->rowCount() >= 0);
120  QVariant variant;
121  model->setData(QModelIndex(), variant, -1);
122  model->setHeaderData(-1, Qt::Horizontal, QVariant());
123  model->setHeaderData(0, Qt::Horizontal, QVariant());
124  model->setHeaderData(999999, Qt::Horizontal, QVariant());
125  QMap<int, QVariant> roles;
126  model->sibling(0, 0, QModelIndex());
127  model->span(QModelIndex());
128  model->supportedDropActions();
129 }
130 
136 void ModelTest::rowCount()
137 {
138  // check top row
139  QModelIndex topIndex = model->index(0, 0, QModelIndex());
140  int rows = model->rowCount(topIndex);
141  Q_ASSERT(rows >= 0);
142  if (rows > 0)
143  Q_ASSERT(model->hasChildren(topIndex) == true);
144 
145  QModelIndex secondLevelIndex = model->index(0, 0, topIndex);
146  if (secondLevelIndex.isValid()) { // not the top level
147  // check a row count where parent is valid
148  rows = model->rowCount(secondLevelIndex);
149  Q_ASSERT(rows >= 0);
150  if (rows > 0)
151  Q_ASSERT(model->hasChildren(secondLevelIndex) == true);
152  }
153 
154  // The models rowCount() is tested more extensively in checkChildren(),
155  // but this catches the big mistakes
156 }
157 
161 void ModelTest::columnCount()
162 {
163  // check top row
164  QModelIndex topIndex = model->index(0, 0, QModelIndex());
165  Q_ASSERT(model->columnCount(topIndex) >= 0);
166 
167  // check a column count where parent is valid
168  QModelIndex childIndex = model->index(0, 0, topIndex);
169  if (childIndex.isValid())
170  Q_ASSERT(model->columnCount(childIndex) >= 0);
171 
172  // columnCount() is tested more extensively in checkChildren(),
173  // but this catches the big mistakes
174 }
175 
179 void ModelTest::hasIndex()
180 {
181  // Make sure that invalid values returns an invalid index
182  Q_ASSERT(model->hasIndex(-2, -2) == false);
183  Q_ASSERT(model->hasIndex(-2, 0) == false);
184  Q_ASSERT(model->hasIndex(0, -2) == false);
185 
186  int rows = model->rowCount();
187  int columns = model->columnCount();
188 
189  // check out of bounds
190  Q_ASSERT(model->hasIndex(rows, columns) == false);
191  Q_ASSERT(model->hasIndex(rows + 1, columns + 1) == false);
192 
193  if (rows > 0)
194  Q_ASSERT(model->hasIndex(0, 0) == true);
195 
196  // hasIndex() is tested more extensively in checkChildren(),
197  // but this catches the big mistakes
198 }
199 
203 void ModelTest::index()
204 {
205  // Make sure that invalid values returns an invalid index
206  Q_ASSERT(model->index(-2, -2) == QModelIndex());
207  Q_ASSERT(model->index(-2, 0) == QModelIndex());
208  Q_ASSERT(model->index(0, -2) == QModelIndex());
209 
210  int rows = model->rowCount();
211  int columns = model->columnCount();
212 
213  if (rows == 0)
214  return;
215 
216  // Catch off by one errors
217  Q_ASSERT(model->index(rows, columns) == QModelIndex());
218  Q_ASSERT(model->index(0, 0).isValid() == true);
219 
220  // Make sure that the same index is *always* returned
221  QModelIndex a = model->index(0, 0);
222  QModelIndex b = model->index(0, 0);
223  Q_ASSERT(a == b);
224 
225  // index() is tested more extensively in checkChildren(),
226  // but this catches the big mistakes
227 }
228 
232 void ModelTest::parent()
233 {
234  // Make sure the model wont crash and will return an invalid QModelIndex
235  // when asked for the parent of an invalid index.
236  Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
237 
238  if (model->rowCount() == 0)
239  return;
240 
241  // Column 0 | Column 1 |
242  // QModelIndex() | |
243  // \- topIndex | topIndex1 |
244  // \- childIndex | childIndex1 |
245 
246  // Common error test #1, make sure that a top level index has a parent
247  // that is a invalid QModelIndex.
248  QModelIndex topIndex = model->index(0, 0, QModelIndex());
249  Q_ASSERT(model->parent(topIndex) == QModelIndex());
250 
251  // Common error test #2, make sure that a second level index has a parent
252  // that is the first level index.
253  if (model->rowCount(topIndex) > 0) {
254  QModelIndex childIndex = model->index(0, 0, topIndex);
255  Q_ASSERT(model->parent(childIndex) == topIndex);
256  }
257 
258  // Common error test #3, the second column should NOT have the same children
259  // as the first column in a row.
260  // Usually the second column shouldn't have children.
261  QModelIndex topIndex1 = model->index(0, 1, QModelIndex());
262  if (model->rowCount(topIndex1) > 0) {
263  QModelIndex childIndex = model->index(0, 0, topIndex);
264  QModelIndex childIndex1 = model->index(0, 0, topIndex1);
265  Q_ASSERT(childIndex != childIndex1);
266  }
267 
268  // Full test, walk n levels deep through the model making sure that all
269  // parent's children correctly specify their parent.
270  checkChildren(QModelIndex());
271 }
272 
287 void ModelTest::checkChildren(const QModelIndex &parent, int currentDepth)
288 {
289  // First just try walking back up the tree.
290  QModelIndex p = parent;
291  while (p.isValid())
292  p = p.parent();
293 
294  // For models that are dynamically populated
295  if (model->canFetchMore(parent)) {
296  fetchingMore = true;
297  model->fetchMore(parent);
298  fetchingMore = false;
299  }
300 
301  int rows = model->rowCount(parent);
302  int columns = model->columnCount(parent);
303 
304  if (rows > 0)
305  Q_ASSERT(model->hasChildren(parent));
306 
307  // Some further testing against rows(), columns(), and hasChildren()
308  Q_ASSERT(rows >= 0);
309  Q_ASSERT(columns >= 0);
310  if (rows > 0)
311  Q_ASSERT(model->hasChildren(parent) == true);
312 
313  //qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows
314  // << "columns:" << columns << "parent column:" << parent.column();
315 
316  Q_ASSERT(model->hasIndex(rows + 1, 0, parent) == false);
317  for (int r = 0; r < rows; ++r) {
318  if (model->canFetchMore(parent)) {
319  fetchingMore = true;
320  model->fetchMore(parent);
321  fetchingMore = false;
322  }
323  Q_ASSERT(model->hasIndex(r, columns + 1, parent) == false);
324  for (int c = 0; c < columns; ++c) {
325  qDebug()<<"index info is r="<<r<<" c="<<c<<"; parent="<<parent<<"; model->index(...)="<<model->index(r,c,parent);
326  Q_ASSERT(model->hasIndex(r, c, parent) == true);
327  QModelIndex index = model->index(r, c, parent);
328  // rowCount() and columnCount() said that it existed...
329  Q_ASSERT(index.isValid() == true);
330 
331  // index() should always return the same index when called twice in a row
332  QModelIndex modifiedIndex = model->index(r, c, parent);
333  Q_ASSERT(index == modifiedIndex);
334 
335  // Make sure we get the same index if we request it twice in a row
336  QModelIndex a = model->index(r, c, parent);
337  QModelIndex b = model->index(r, c, parent);
338  Q_ASSERT(a == b);
339 
340  // Some basic checking on the index that is returned
341  Q_ASSERT(index.model() == model);
342  Q_ASSERT(index.row() == r);
343  Q_ASSERT(index.column() == c);
344  // While you can technically return a QVariant usually this is a sign
345  // of an bug in data() Disable if this really is ok in your model.
346  //Q_ASSERT(model->data(index, Qt::DisplayRole).isValid() == true);
347 
348  // If the next test fails here is some somewhat useful debug you play with.
349 
350  if (model->parent(index) != parent) {
351  qDebug() << "Bad parent!";
352  qDebug() << r << c << currentDepth << model->data(index).toString()
353  << model->data(parent).toString();
354  qDebug() << index << parent << model->parent(index);
355  // And a view that you can even use to show the model.
356  //QTreeView view;
357  //view.setModel(model);
358  //view.show();
359  }
360 
361  // Check that we can get back our real parent.
362  QModelIndex p = model->parent(index);
363  //qDebug() << "child:" << index;
364  //qDebug() << p;
365  //qDebug() << parent;
366  Q_ASSERT(model->parent(index) == parent);
367 
368  // recursively go down the children
369  if (model->hasChildren(index) && currentDepth < 10 ) {
370  //qDebug() << r << c << "has children" << model->rowCount(index);
371  checkChildren(index, ++currentDepth);
372  }/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/
373 
374  // make sure that after testing the children that the index doesn't change.
375  QModelIndex newerIndex = model->index(r, c, parent);
376  Q_ASSERT(index == newerIndex);
377  }
378  }
379 }
380 
384 void ModelTest::data()
385 {
386  // Invalid index should return an invalid qvariant
387  Q_ASSERT(!model->data(QModelIndex()).isValid());
388 
389  if (model->rowCount() == 0)
390  return;
391 
392  // A valid index should have a valid QVariant data
393  Q_ASSERT(model->index(0, 0).isValid());
394 
395  // shouldn't be able to set data on an invalid index
396  Q_ASSERT(model->setData(QModelIndex(), QLatin1String("foo"), Qt::DisplayRole) == false);
397 
398  // General Purpose roles that should return a QString
399  QVariant variant = model->data(model->index(0, 0), Qt::ToolTipRole);
400  if (variant.isValid()) {
401  Q_ASSERT(qVariantCanConvert<QString>(variant));
402  }
403  variant = model->data(model->index(0, 0), Qt::StatusTipRole);
404  if (variant.isValid()) {
405  Q_ASSERT(qVariantCanConvert<QString>(variant));
406  }
407  variant = model->data(model->index(0, 0), Qt::WhatsThisRole);
408  if (variant.isValid()) {
409  Q_ASSERT(qVariantCanConvert<QString>(variant));
410  }
411 
412  // General Purpose roles that should return a QSize
413  variant = model->data(model->index(0, 0), Qt::SizeHintRole);
414  if (variant.isValid()) {
415  Q_ASSERT(qVariantCanConvert<QSize>(variant));
416  }
417 
418  // General Purpose roles that should return a QFont
419  QVariant fontVariant = model->data(model->index(0, 0), Qt::FontRole);
420  if (fontVariant.isValid()) {
421  Q_ASSERT(qVariantCanConvert<QFont>(fontVariant));
422  }
423 
424  // Check that the alignment is one we know about
425  QVariant textAlignmentVariant = model->data(model->index(0, 0), Qt::TextAlignmentRole);
426  if (textAlignmentVariant.isValid()) {
427  int alignment = textAlignmentVariant.toInt();
428  Q_ASSERT(alignment == Qt::AlignLeft ||
429  alignment == Qt::AlignRight ||
430  alignment == Qt::AlignHCenter ||
431  alignment == Qt::AlignJustify ||
432  alignment == Qt::AlignTop ||
433  alignment == Qt::AlignBottom ||
434  alignment == Qt::AlignVCenter ||
435  alignment == Qt::AlignCenter ||
436  alignment == Qt::AlignAbsolute ||
437  alignment == Qt::AlignLeading ||
438  alignment == Qt::AlignTrailing);
439  }
440 
441  // General Purpose roles that should return a QColor
442  QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundColorRole);
443  if (colorVariant.isValid()) {
444  Q_ASSERT(qVariantCanConvert<QColor>(colorVariant));
445  }
446 
447  colorVariant = model->data(model->index(0, 0), Qt::TextColorRole);
448  if (colorVariant.isValid()) {
449  Q_ASSERT(qVariantCanConvert<QColor>(colorVariant));
450  }
451 
452  // Check that the "check state" is one we know about.
453  QVariant checkStateVariant = model->data(model->index(0, 0), Qt::CheckStateRole);
454  if (checkStateVariant.isValid()) {
455  int state = checkStateVariant.toInt();
456  Q_ASSERT(state == Qt::Unchecked ||
457  state == Qt::PartiallyChecked ||
458  state == Qt::Checked);
459  }
460 }
461 
467 void ModelTest::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
468 {
469  Q_UNUSED(end);
470  Changing c;
471  c.parent = parent;
472  c.oldSize = model->rowCount(parent);
473  c.last = model->data(model->index(start - 1, 0, parent));
474  c.next = model->data(model->index(start, 0, parent));
475  insert.push(c);
476 }
477 
483 void ModelTest::rowsInserted(const QModelIndex & parent, int start, int end)
484 {
485  Changing c = insert.pop();
486  Q_ASSERT(c.parent == parent);
487  Q_ASSERT(c.oldSize + (end - start + 1) == model->rowCount(parent));
488  Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
489  /*
490  if (c.next != model->data(model->index(end + 1, 0, c.parent))) {
491  qDebug() << start << end;
492  for (int i=0; i < model->rowCount(); ++i)
493  qDebug() << model->index(i, 0).data().toString();
494  qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent));
495  }
496  */
497  Q_ASSERT(c.next == model->data(model->index(end + 1, 0, c.parent)));
498 }
499 
500 void ModelTest::layoutAboutToBeChanged()
501 {
502  for (int i = 0; i < qBound(0, model->rowCount(), 100); ++i)
503  changing.append(QPersistentModelIndex(model->index(i, 0)));
504 }
505 
506 void ModelTest::layoutChanged()
507 {
508  for (int i = 0; i < changing.count(); ++i) {
509  QPersistentModelIndex p = changing[i];
510  Q_ASSERT(p == model->index(p.row(), p.column(), p.parent()));
511  }
512  changing.clear();
513 }
514 
520 void ModelTest::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
521 {
522  Changing c;
523  c.parent = parent;
524  c.oldSize = model->rowCount(parent);
525  c.last = model->data(model->index(start - 1, 0, parent));
526  c.next = model->data(model->index(end + 1, 0, parent));
527  remove.push(c);
528 }
529 
535 void ModelTest::rowsRemoved(const QModelIndex & parent, int start, int end)
536 {
537  Changing c = remove.pop();
538  Q_ASSERT(c.parent == parent);
539  Q_ASSERT(c.oldSize - (end - start + 1) == model->rowCount(parent));
540  Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
541  Q_ASSERT(c.next == model->data(model->index(start, 0, c.parent)));
542 }
543 
544 
545 
546 
547 #endif
Q_DECLARE_METATYPE(KLFUnitChooser::Unit)
toInt(bool *ok=0)
data(int role=Qt::DisplayRole)

Generated by doxygen 1.8.8