~ubuntu-branches/debian/sid/qbzr/sid

« back to all changes in this revision

Viewing changes to lib/tests/modeltest.py

  • Committer: Bazaar Package Importer
  • Author(s): Jelmer Vernooij
  • Date: 2009-12-05 01:20:38 UTC
  • Revision ID: james.westby@ubuntu.com-20091205012038-41f57s3ecv2r34lz
Tags: upstream-0.16
ImportĀ upstreamĀ versionĀ 0.16

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
import sip
 
25
from PyQt4 import QtCore, QtGui
 
26
 
 
27
 
 
28
class ModelTest(QtCore.QObject):
 
29
    def __init__(self, _model, parent):
 
30
        """
 
31
        Connect to all of the models signals, Whenever anything happens recheck everything.
 
32
        """
 
33
        QtCore.QObject.__init__(self,parent)
 
34
        self._model = _model
 
35
        self.model = sip.cast(_model, QtCore.QAbstractItemModel)
 
36
        self.insert = []
 
37
        self.remove = []
 
38
        self.fetchingMore = False
 
39
        assert(self.model)
 
40
 
 
41
        self.connect( self.model, QtCore.SIGNAL("columnsAboutToBeInserted(const QtCore.QModelIndex&, int, int)"), self.runAllTests)
 
42
        self.connect( self.model, QtCore.SIGNAL("columnsAboutToBeRemoved(const QtCore.QModelIndex&, int, int)"), self.runAllTests)
 
43
        self.connect( self.model, QtCore.SIGNAL("columnsBeInserted(const QtCore.QModelIndex&, int, int)"), self.runAllTests)
 
44
        self.connect( self.model, QtCore.SIGNAL("columnsRemoved(const QtCore.QModelIndex&, int, int)"), self.runAllTests)
 
45
        self.connect( self.model, QtCore.SIGNAL("dataChanged(const QtCore.QModelIndex&, const QtCore.QModelIndex&)"), self.runAllTests)
 
46
        self.connect( self.model, QtCore.SIGNAL("headerDataChanged(Qt::Orientation, int, int)"), self.runAllTests)
 
47
        self.connect( self.model, QtCore.SIGNAL("layoutAboutToBeChanged()"), self.runAllTests)
 
48
        self.connect( self.model, QtCore.SIGNAL("layoutChanged()"), self.runAllTests)
 
49
        self.connect( self.model, QtCore.SIGNAL("modelReset()"), self.runAllTests)
 
50
        self.connect( self.model, QtCore.SIGNAL("rowsAboutToBeInserted(const QtCore.QModelIndex&, int, int)"), self.runAllTests)
 
51
        self.connect( self.model, QtCore.SIGNAL("rowsAboutToBeRemoved(const QtCore.QModelIndex&, int, int)"), self.runAllTests)
 
52
        self.connect( self.model, QtCore.SIGNAL("rowsBeInserted(const QtCore.QModelIndex&, int, int)"), self.runAllTests)
 
53
        self.connect( self.model, QtCore.SIGNAL("rowsRemoved(const QtCore.QModelIndex&, int, int)"), self.runAllTests)
 
54
 
 
55
        # Special checks for inserting/removing
 
56
        self.connect( self.model, QtCore.SIGNAL("rowsAboutToBeInserted(const QtCore.QModelIndex&, int, int)"), self.rowsAboutToBeInserted)
 
57
        self.connect( self.model, QtCore.SIGNAL("rowsAboutToBeRemoved(const QtCore.QModelIndex&, int, int)"), self.rowsAboutToBeRemoved)
 
58
        self.connect( self.model, QtCore.SIGNAL("rowsBeInserted(const QtCore.QModelIndex&, int, int)"), self.rowsInserted)
 
59
        self.connect( self.model, QtCore.SIGNAL("rowsRemoved(const QtCore.QModelIndex&, int, int)"), self.rowsRemoved)
 
60
        self.runAllTests()
 
61
 
 
62
    def nonDestructiveBasicTest(self):
 
63
        """
 
64
        nonDestructiveBasicTest tries to call a number of the basic functions (not all)
 
65
        to make sure the model doesn't outright segfault, testing the functions that makes sense.
 
66
        """
 
67
        assert(self.model.buddy(QtCore.QModelIndex()) == QtCore.QModelIndex())
 
68
        self.model.canFetchMore(QtCore.QModelIndex())
 
69
        assert(self.model.columnCount(QtCore.QModelIndex()) >= 0)
 
70
        assert(self.model.data(QtCore.QModelIndex(), QtCore.Qt.DisplayRole) == QtCore.QVariant())
 
71
        self.fetchingMore = True
 
72
        self.model.fetchMore(QtCore.QModelIndex())
 
73
        self.fetchingMore = False
 
74
        flags = self.model.flags(QtCore.QModelIndex())
 
75
        assert( int(flags & QtCore.Qt.ItemIsEnabled) == QtCore.Qt.ItemIsEnabled or int(flags & QtCore.Qt.ItemIsEnabled ) == 0 )
 
76
        self.model.hasChildren(QtCore.QModelIndex())
 
77
        self.model.hasIndex(0,0)
 
78
        self.model.headerData(0,QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole)
 
79
        self.model.index(0,0, QtCore.QModelIndex())
 
80
        self.model.itemData(QtCore.QModelIndex())
 
81
        cache = QtCore.QVariant()
 
82
        self.model.match(QtCore.QModelIndex(), -1, cache)
 
83
        self.model.mimeTypes()
 
84
        assert(self.model.parent(QtCore.QModelIndex()) == QtCore.QModelIndex())
 
85
        assert(self.model.rowCount(QtCore.QModelIndex()) >= 0)
 
86
        variant = QtCore.QVariant()
 
87
        self.model.setData(QtCore.QModelIndex(), variant, -1)
 
88
        self.model.setHeaderData(-1, QtCore.Qt.Horizontal, QtCore.QVariant())
 
89
        self.model.setHeaderData(0, QtCore.Qt.Horizontal, QtCore.QVariant())
 
90
        self.model.setHeaderData(999999, QtCore.Qt.Horizontal, QtCore.QVariant())
 
91
        self.model.sibling(0,0,QtCore.QModelIndex())
 
92
        self.model.span(QtCore.QModelIndex())
 
93
        self.model.supportedDropActions()
 
94
 
 
95
    def rowCount(self):
 
96
        """
 
97
        Tests self.model's implementation of QtCore.QAbstractItemModel::rowCount() and hasChildren()
 
98
        
 
99
        self.models that are dynamically populated are not as fully tested here.
 
100
        """
 
101
        # check top row
 
102
        topindex = self.model.index(0,0,QtCore.QModelIndex())
 
103
        rows = self.model.rowCount(topindex)
 
104
        assert(rows >= 0)
 
105
        if rows > 0:
 
106
            assert(self.model.hasChildren(topindex) == True )
 
107
 
 
108
        secondlvl = self.model.index(0,0,topindex)
 
109
        if secondlvl.isValid():
 
110
            # check a row count where parent is valid
 
111
            rows = self.model.rowCount(secondlvl)
 
112
            assert(rows >= 0)
 
113
            if rows > 0:
 
114
                assert(self.model.hasChildren(secondlvl) == True)
 
115
        
 
116
        # The self.models rowCount() is tested more extensively in checkChildren,
 
117
        # but this catches the big mistakes
 
118
 
 
119
    def columnCount(self):
 
120
        """
 
121
        Tests self.model's implementation of QtCore.QAbstractItemModel::columnCount() and hasChildren()
 
122
        """
 
123
        # check top row
 
124
        topidx = self.model.index(0,0,QtCore.QModelIndex())
 
125
        assert(self.model.columnCount(topidx) >= 0)
 
126
 
 
127
        # check a column count where parent is valid
 
128
        childidx = self.model.index(0,0,topidx)
 
129
        if childidx.isValid() :
 
130
            assert(self.model.columnCount(childidx) >= 0)
 
131
 
 
132
        # columnCount() is tested more extensively in checkChildren,
 
133
        # but this catches the big mistakes
 
134
 
 
135
    def hasIndex(self):
 
136
        """
 
137
        Tests self.model's implementation of QtCore.QAbstractItemModel::hasIndex()
 
138
        """
 
139
        # Make sure that invalid values returns an invalid index
 
140
        assert(self.model.hasIndex(-2,-2) == False)
 
141
        assert(self.model.hasIndex(-2,0) == False)
 
142
        assert(self.model.hasIndex(0,-2) == False)
 
143
 
 
144
        rows = self.model.rowCount(QtCore.QModelIndex())
 
145
        cols = self.model.columnCount(QtCore.QModelIndex())
 
146
 
 
147
        # check out of bounds
 
148
        assert(self.model.hasIndex(rows,cols) == False)
 
149
        assert(self.model.hasIndex(rows+1,cols+1) == False)
 
150
 
 
151
        if rows > 0:
 
152
            assert(self.model.hasIndex(0,0) == True)
 
153
 
 
154
        # hasIndex() is tested more extensively in checkChildren()
 
155
        # but this catches the big mistakes
 
156
 
 
157
    def index(self):
 
158
        """
 
159
        Tests self.model's implementation of QtCore.QAbstractItemModel::index()
 
160
        """
 
161
        # Make sure that invalid values returns an invalid index
 
162
        assert(self.model.index(-2,-2, QtCore.QModelIndex()) == QtCore.QModelIndex())
 
163
        assert(self.model.index(-2,0, QtCore.QModelIndex()) == QtCore.QModelIndex())
 
164
        assert(self.model.index(0,-2, QtCore.QModelIndex()) == QtCore.QModelIndex())
 
165
 
 
166
        rows = self.model.rowCount(QtCore.QModelIndex())
 
167
        cols = self.model.columnCount(QtCore.QModelIndex())
 
168
 
 
169
        if rows == 0:
 
170
            return
 
171
 
 
172
        # Catch off by one errors
 
173
        assert(self.model.index(rows,cols, QtCore.QModelIndex()) == QtCore.QModelIndex())
 
174
        assert(self.model.index(0,0, QtCore.QModelIndex()).isValid() == True)
 
175
 
 
176
        # Make sure that the same index is *always* returned
 
177
        a = self.model.index(0,0, QtCore.QModelIndex())
 
178
        b = self.model.index(0,0, QtCore.QModelIndex())
 
179
        assert(a==b)
 
180
 
 
181
        # index() is tested more extensively in checkChildren()
 
182
        # but this catches the big mistakes
 
183
 
 
184
    def parent(self):
 
185
        """
 
186
        Tests self.model's implementation of QtCore.QAbstractItemModel::parent()
 
187
        """
 
188
        # Make sure the self.model wont crash and will return an invalid QtCore.QModelIndex
 
189
        # when asked for the parent of an invalid index
 
190
        assert(self.model.parent(QtCore.QModelIndex()) == QtCore.QModelIndex())
 
191
 
 
192
        if self.model.rowCount(QtCore.QModelIndex()) == 0:
 
193
            return;
 
194
 
 
195
        # Column 0              | Column 1  |
 
196
        # QtCore.Qself.modelIndex()         |           |
 
197
        #    \- topidx          | topidx1   |
 
198
        #         \- childix    | childidx1 |
 
199
 
 
200
        # Common error test #1, make sure that a top level index has a parent
 
201
        # that is an invalid QtCore.Qself.modelIndex
 
202
        topidx = self.model.index(0,0,QtCore.QModelIndex())
 
203
        assert(self.model.parent(topidx) == QtCore.QModelIndex())
 
204
 
 
205
        # Common error test #2, make sure that a second level index has a parent
 
206
        # that is the first level index
 
207
        if self.model.rowCount(topidx) > 0 :
 
208
            childidx = self.model.index(0,0,topidx)
 
209
            assert(self.model.parent(childidx) == topidx)
 
210
 
 
211
        # Common error test #3, the second column should NOT have the same children
 
212
        # as the first column in a row
 
213
        # Usually the second column shouldn't have children
 
214
        topidx1 = self.model.index(0,1,QtCore.QModelIndex())
 
215
        if self.model.rowCount(topidx1) > 0:
 
216
            childidx = self.model.index(0,0,topidx)
 
217
            childidx1 = self.model.index(0,0,topidx1)
 
218
            assert(childidx != childidx1)
 
219
 
 
220
        # Full test, walk n levels deep through the self.model making sure that all
 
221
        # parent's children correctly specify their parent
 
222
        self.checkChildren(QtCore.QModelIndex())
 
223
 
 
224
    def data(self):
 
225
        """
 
226
        Tests self.model's implementation of QtCore.QAbstractItemModel::data()
 
227
        """
 
228
        # Invalid index should return an invalid qvariant
 
229
        assert( not self.model.data(QtCore.QModelIndex(), QtCore.Qt.DisplayRole).isValid())
 
230
 
 
231
        if self.model.rowCount(QtCore.QModelIndex()) == 0:
 
232
            return
 
233
 
 
234
        # A valid index should have a valid QtCore.QVariant data
 
235
        assert( self.model.index(0,0, QtCore.QModelIndex()).isValid())
 
236
 
 
237
        # shouldn't be able to set data on an invalid index
 
238
        assert( self.model.setData( QtCore.QModelIndex(), QtCore.QVariant("foo"), QtCore.Qt.DisplayRole) == False)
 
239
 
 
240
        # General Purpose roles that should return a QString
 
241
        variant = self.model.data(self.model.index(0,0,QtCore.QModelIndex()), QtCore.Qt.ToolTipRole)
 
242
        if variant.isValid():
 
243
            assert( variant.canConvert( QtCore.QVariant.String ) )
 
244
        variant = self.model.data(self.model.index(0,0,QtCore.QModelIndex()), QtCore.Qt.StatusTipRole)
 
245
        if variant.isValid():
 
246
            assert( variant.canConvert( QtCore.QVariant.String ) )
 
247
        variant = self.model.data(self.model.index(0,0,QtCore.QModelIndex()), QtCore.Qt.WhatsThisRole)
 
248
        if variant.isValid():
 
249
            assert( variant.canConvert( QtCore.QVariant.String ) )
 
250
        
 
251
        # General Purpose roles that should return a QSize
 
252
        variant = self.model.data(self.model.index(0,0,QtCore.QModelIndex()), QtCore.Qt.SizeHintRole)
 
253
        if variant.isValid():
 
254
            assert( variant.canConvert( QtCore.QVariant.Size ) )
 
255
 
 
256
        # General Purpose roles that should return a QFont
 
257
        variant = self.model.data(self.model.index(0,0,QtCore.QModelIndex()), QtCore.Qt.FontRole)
 
258
        if variant.isValid():
 
259
            assert( variant.canConvert( QtCore.QVariant.Font ) )
 
260
        
 
261
        # Check that the alignment is one we know about
 
262
        variant = self.model.data(self.model.index(0,0,QtCore.QModelIndex()), QtCore.Qt.TextAlignmentRole)
 
263
        if variant.isValid():
 
264
            alignment = variant.toInt()[0]
 
265
            assert( alignment == QtCore.Qt.AlignLeft or
 
266
                alignment == QtCore.Qt.AlignRight or
 
267
                alignment == QtCore.Qt.AlignHCenter or
 
268
                alignment == QtCore.Qt.AlignJustify)
 
269
 
 
270
        # General Purpose roles that should return a QColor
 
271
        variant = self.model.data(self.model.index(0,0,QtCore.QModelIndex()), QtCore.Qt.BackgroundColorRole)
 
272
        if variant.isValid():
 
273
            assert( variant.canConvert( QtCore.QVariant.Color ) )
 
274
        variant = self.model.data(self.model.index(0,0,QtCore.QModelIndex()), QtCore.Qt.TextColorRole)
 
275
        if variant.isValid():
 
276
            assert( variant.canConvert( QtCore.QVariant.Color ) )
 
277
 
 
278
        # Check that the "check state" is one we know about.
 
279
        variant = self.model.data(self.model.index(0,0,QtCore.QModelIndex()), QtCore.Qt.CheckStateRole)
 
280
        if variant.isValid():
 
281
            state = variant.toInt()[0]
 
282
            assert( state == QtCore.Qt.Unchecked or
 
283
                state == QtCore.Qt.PartiallyChecked or
 
284
                state == QtCore.Qt.Checked )
 
285
 
 
286
 
 
287
    def runAllTests(self):
 
288
        if self.fetchingMore:
 
289
            return
 
290
        self.nonDestructiveBasicTest()
 
291
        self.rowCount()
 
292
        self.columnCount()
 
293
        self.hasIndex()
 
294
        self.index()
 
295
        self.parent()
 
296
        self.data()
 
297
 
 
298
    def rowsAboutToBeInserted(self, parent, start, end):
 
299
        """
 
300
        Store what is about to be inserted to make sure it actually happens
 
301
        """
 
302
        c = {}
 
303
        c['parent'] = parent
 
304
        c['oldSize'] = self.model.rowCount(parent)
 
305
        c['last'] = self.model.data(model.index(start-1, 0, parent))
 
306
        c['next'] = self.model.data(model.index(start, 0, parent))
 
307
        insert.append(c)
 
308
 
 
309
    def rowsInserted(self, parent, start, end):
 
310
        """
 
311
        Confirm that what was said was going to happen actually did
 
312
        """
 
313
        c = insert.pop()
 
314
        assert(c['parent'] == parent)
 
315
        assert(c['oldSize'] + (end - start + 1) == self.model.rowCount(parent))
 
316
        assert(c['last'] == self.model.data(model.index(start-1, 0, c['parent'])))
 
317
 
 
318
        # if c['next'] != self.model.data(model.index(end+1, 0, c['parent'])):
 
319
        #   qDebug << start << end
 
320
        #   for i in range(0, self.model.rowCount(QtCore.QModelIndex())):
 
321
        #       qDebug << self.model.index(i, 0).data().toString()
 
322
        #   qDebug() << c['next'] << self.model.data(model.index(end+1, 0, c['parent']))
 
323
 
 
324
        assert(c['next'] == self.model.data(model.index(end+1, 0, c['parent'])))
 
325
 
 
326
    def rowsAboutToBeRemoved(self, parent, start, end):
 
327
        """
 
328
        Store what is about to be inserted to make sure it actually happens
 
329
        """
 
330
        c = {}
 
331
        c['parent'] = parent
 
332
        c['oldSize'] = self.model.rowCount(parent)
 
333
        c['last'] = self.model.data(model.index(start-1, 0, parent))
 
334
        c['next'] = self.model.data(model.index(end+1, 0, parent))
 
335
        remove.append(c)
 
336
 
 
337
    def rowsRemoved(self, parent, start, end):
 
338
        """
 
339
        Confirm that what was said was going to happen actually did
 
340
        """
 
341
        c = remove.pop()
 
342
        assert(c['parent'] == parent)
 
343
        assert(c['oldSize'] - (end - start + 1) == self.model.rowCount(parent))
 
344
        assert(c['last'] == self.model.data(model.index(start-1, 0, c['parent'])))
 
345
        assert(c['next'] == self.model.data(model.index(start, 0, c['parent'])))
 
346
 
 
347
    def checkChildren(self, parent, depth = 0):
 
348
        """
 
349
        Called from parent() test.
 
350
 
 
351
        A self.model that returns an index of parent X should also return X when asking
 
352
        for the parent of the index
 
353
 
 
354
        This recursive function does pretty extensive testing on the whole self.model in an
 
355
        effort to catch edge cases.
 
356
 
 
357
        This function assumes that rowCount(QtCore.QModelIndex()), columnCount(QtCore.QModelIndex()) and index() already work.
 
358
        If they have a bug it will point it out, but the above tests should have already
 
359
        found the basic bugs because it is easier to figure out the problem in
 
360
        those tests then this one
 
361
        """
 
362
        # First just try walking back up the tree.
 
363
        p = parent;
 
364
        while p.isValid():
 
365
            p = p.parent()
 
366
 
 
367
        #For self.models that are dynamically populated
 
368
        if self.model.canFetchMore( parent ):
 
369
            self.fetchingMore = True
 
370
            self.model.fetchMore(parent)
 
371
            self.fetchingMore = False
 
372
 
 
373
        rows = self.model.rowCount(parent)
 
374
        cols = self.model.columnCount(parent)
 
375
 
 
376
        if rows > 0:
 
377
            assert(self.model.hasChildren(parent))
 
378
 
 
379
        # Some further testing against rows(), columns, and hasChildren()
 
380
        assert( rows >= 0 )
 
381
        assert( cols >= 0 )
 
382
 
 
383
        if rows > 0:
 
384
            assert(self.model.hasChildren(parent) == True)
 
385
 
 
386
        # qDebug() << "parent:" << self.model.data(parent).toString() << "rows:" << rows
 
387
        #          << "columns:" << cols << "parent column:" << parent.column()
 
388
 
 
389
        assert( self.model.hasIndex( rows+1, 0, parent) == False)
 
390
        for r in range(0,rows):
 
391
            if self.model.canFetchMore(parent):
 
392
                self.fetchingMore = True
 
393
                self.model.fetchMore(parent)
 
394
                self.fetchingMore = False
 
395
            assert(self.model.hasIndex(r,cols+1,parent) == False)
 
396
            for c in range(0,cols):
 
397
                assert(self.model.hasIndex(r,c,parent))
 
398
                index = self.model.index(r,c,parent)
 
399
                # rowCount(QtCore.QModelIndex()) and columnCount(QtCore.QModelIndex()) said that it existed...
 
400
                assert(index.isValid() == True)
 
401
 
 
402
                # index() should always return the same index when called twice in a row
 
403
                modIdx = self.model.index(r,c,parent)
 
404
                assert(index == modIdx)
 
405
 
 
406
                # Make sure we get the same index if we request it twice in a row
 
407
                a = self.model.index(r,c,parent)
 
408
                b = self.model.index(r,c,parent)
 
409
                assert( a == b )
 
410
 
 
411
                # Some basic checking on the index that is returned
 
412
                # assert( index.model() == self.model )
 
413
                # This raises an error that is not part of the qbzr code.
 
414
                # see http://www.opensubscriber.com/message/pyqt@riverbankcomputing.com/10335500.html
 
415
                assert( index.row() == r )
 
416
                assert( index.column() == c )
 
417
                # While you can technically return a QtCore.QVariant usually this is a sign
 
418
                # if an bug in data() Disable if this really is ok in your self.model
 
419
                assert( self.model.data(index, QtCore.Qt.DisplayRole).isValid() == True )
 
420
 
 
421
                #if the next test fails here is some somehwat useful debug you play with
 
422
                # if self.model.parent(index) != parent:
 
423
                #   qDebug() << r << c << depth << self.model.data(index).toString()
 
424
                #        << self.model.data(parent).toString()
 
425
                #   qDebug() << index << parent << self.model.parent(index)
 
426
                #   # And a view that you can even use to show the self.model
 
427
                #   # view = QtGui.QTreeView()
 
428
                #   # view.setself.model(model)
 
429
                #   # view.show()
 
430
                #
 
431
 
 
432
                # Check that we can get back our real parent
 
433
                p = self.model.parent( index )
 
434
                assert( p.internalId() == parent.internalId() )
 
435
                assert( p.row() == parent.row() )
 
436
 
 
437
                # recursively go down the children
 
438
                if self.model.hasChildren(index) and depth < 10:
 
439
                    # qDebug() << r << c << "hasChildren" << self.model.rowCount(index)
 
440
                    self.checkChildren(index, ++depth)
 
441
                #else:
 
442
                #   if depth >= 10:
 
443
                #       qDebug() << "checked 10 deep"
 
444
 
 
445
                # Make sure that after testing the children that the index doesn't change
 
446
                newIdx = self.model.index(r,c,parent)
 
447
                assert(index == newIdx)
 
448
 
 
449