def _on_rows_removed(self, parent, start, end): """Confirm that what was said was going to happen actually did.""" c = self._remove.pop() last_data = self._model.data(self._model.index(start - 1, 0, c.parent)) next_data = self._model.data(self._model.index(start, 0, c.parent)) current_size = self._model.rowCount(parent) expected_size = c.old_size - (end - start + 1) self._debug("rows removed: start {}, end {}".format(start, end)) self._debug(" from rowsAboutToBeRemoved: parent {}, " "size {} (-> {} expected), " "next data {!r}, last data {!r}".format( self._modelindex_debug(c.parent), c.old_size, expected_size, qt_api.extract_from_variant(c.next), qt_api.extract_from_variant(c.last))) self._debug(" now in rowsRemoved: parent {}, size {}, " "next data {!r}, last data {!r}".format( self._modelindex_debug(parent), current_size, qt_api.extract_from_variant(next_data), qt_api.extract_from_variant(last_data))) if not qt_api.QtCore.qVersion().startswith('4.'): # Skipping this on Qt4 as the parent changes for some reason # see _on_rows_inserted for details assert c.parent == parent assert current_size == expected_size assert c.last == last_data assert c.next == next_data
def _on_rows_inserted(self, parent, start, end): """Confirm that what was said was going to happen actually did.""" c = self._insert.pop() last_data = ( self._model.data(self._model.index(start - 1, 0, parent)) if start - 1 >= 0 else None ) next_data = ( self._model.data(self._model.index(end + 1, 0, c.parent)) if end + 1 < self._model.rowCount(c.parent) else None ) expected_size = c.old_size + (end - start + 1) current_size = self._model.rowCount(parent) self._debug("rows inserted: start {}, end {}".format(start, end)) self._debug( " from rowsAboutToBeInserted: parent {}, " "size {} (-> {} expected), " "next data {!r}, last data {!r}".format( self._modelindex_debug(c.parent), c.old_size, expected_size, qt_api.extract_from_variant(c.next), qt_api.extract_from_variant(c.last), ) ) self._debug( " now in rowsInserted: parent {}, size {}, " "next data {!r}, last data {!r}".format( self._modelindex_debug(parent), current_size, qt_api.extract_from_variant(next_data), qt_api.extract_from_variant(last_data), ) ) if not qt_api.QtCore.qVersion().startswith("4."): # Skipping this on Qt4 as the parent changes for some reason: # modeltest: rows about to be inserted: [...] # parent <invalid> (0x7f8f540eacf8), [...] # [...] # modeltest: from rowsAboutToBeInserted: # parent 0/0 None (0x7f8f540eacf8), [...] # modeltest: now in rowsInserted: # parent <invalid> (0x7f8f60a96cf8) [...] assert c.parent == parent for ii in range(start, end + 1): idx = self._model.index(ii, 0, parent) self._debug(" item {} inserted: {}".format(ii, self._modelindex_debug(idx))) self._debug("") assert current_size == expected_size if last_data is not None: assert c.last == last_data if next_data is not None: assert c.next == next_data
def _test_data(self): """Test model's implementation of data()""" # Invalid index should return an invalid qvariant value = self._model.data(qt_api.QtCore.QModelIndex(), qt_api.QtCore.Qt.DisplayRole) assert qt_api.extract_from_variant(value) is None if self._model.rowCount() == 0: return # A valid index should have a valid QVariant data assert self._model.index(0, 0).isValid() # shouldn't be able to set data on an invalid index ok = self._model.setData(qt_api.QtCore.QModelIndex(), "foo", qt_api.QtCore.Qt.DisplayRole) assert not ok types = [ (qt_api.QtCore.Qt.ToolTipRole, str), (qt_api.QtCore.Qt.StatusTipRole, str), (qt_api.QtCore.Qt.WhatsThisRole, str), (qt_api.QtCore.Qt.SizeHintRole, qt_api.QtCore.QSize), (qt_api.QtCore.Qt.FontRole, qt_api.QtGui.QFont), (qt_api.QtCore.Qt.BackgroundColorRole, (qt_api.QtGui.QColor, qt_api.QtGui.QBrush)), (qt_api.QtCore.Qt.TextColorRole, (qt_api.QtGui.QColor, qt_api.QtGui.QBrush)), ] # General purpose roles with a fixed expected type for role, typ in types: data = self._model.data(self._model.index(0, 0), role) assert data == None or isinstance(data, typ), role # Check that the alignment is one we know about alignment = self._model.data(self._model.index(0, 0), qt_api.QtCore.Qt.TextAlignmentRole) alignment = qt_api.extract_from_variant(alignment) if alignment is not None: try: alignment = int(alignment) except (TypeError, ValueError): assert 0, '%r should be a TextAlignmentRole enum' % alignment mask = int(qt_api.QtCore.Qt.AlignHorizontal_Mask | qt_api.QtCore.Qt.AlignVertical_Mask) assert alignment == alignment & mask # Check that the "check state" is one we know about. state = self._model.data(self._model.index(0, 0), qt_api.QtCore.Qt.CheckStateRole) assert state in [ None, qt_api.QtCore.Qt.Unchecked, qt_api.QtCore.Qt.PartiallyChecked, qt_api.QtCore.Qt.Checked ]
def test_qvariant(tmpdir): """Test that make_variant and extract_from_variant work in the same way across all supported Qt bindings. """ settings = qt_api.QtCore.QSettings(str(tmpdir / 'foo.ini'), qt_api.QtCore.QSettings.IniFormat) settings.setValue('int', qt_api.make_variant(42)) settings.setValue('str', qt_api.make_variant('Hello')) settings.setValue('empty', qt_api.make_variant()) assert qt_api.extract_from_variant(settings.value('int')) == 42 assert qt_api.extract_from_variant(settings.value('str')) == 'Hello' assert qt_api.extract_from_variant(settings.value('empty')) is None
def test_qvariant(tmpdir): """Test that make_variant and extract_from_variant work in the same way across all supported Qt bindings. """ settings = qt_api.QtCore.QSettings(str(tmpdir / "foo.ini"), qt_api.QtCore.QSettings.IniFormat) settings.setValue("int", qt_api.make_variant(42)) settings.setValue("str", qt_api.make_variant("Hello")) settings.setValue("empty", qt_api.make_variant()) assert qt_api.extract_from_variant(settings.value("int")) == 42 assert qt_api.extract_from_variant(settings.value("str")) == "Hello" assert qt_api.extract_from_variant(settings.value("empty")) is None
def _test_data(self): """Test model's implementation of data()""" # Invalid index should return an invalid qvariant value = self._model.data(qt_api.QtCore.QModelIndex(), qt_api.QtCore.Qt.DisplayRole) assert qt_api.extract_from_variant(value) is None if self._model.rowCount() == 0: return # A valid index should have a valid QVariant data assert self._model.index(0, 0).isValid() # shouldn't be able to set data on an invalid index ok = self._model.setData(qt_api.QtCore.QModelIndex(), "foo", qt_api.QtCore.Qt.DisplayRole) assert not ok types = [ (qt_api.QtCore.Qt.ToolTipRole, str), (qt_api.QtCore.Qt.StatusTipRole, str), (qt_api.QtCore.Qt.WhatsThisRole, str), (qt_api.QtCore.Qt.SizeHintRole, qt_api.QtCore.QSize), (qt_api.QtCore.Qt.FontRole, qt_api.QtGui.QFont), (qt_api.QtCore.Qt.BackgroundColorRole, qt_api.QtGui.QColor), (qt_api.QtCore.Qt.TextColorRole, qt_api.QtGui.QColor), ] # General purpose roles with a fixed expected type for role, typ in types: data = self._model.data(self._model.index(0, 0), role) assert data == None or isinstance(data, typ), role # Check that the alignment is one we know about alignment = self._model.data(self._model.index(0, 0), qt_api.QtCore.Qt.TextAlignmentRole) alignment = qt_api.extract_from_variant(alignment) if alignment is not None: try: alignment = int(alignment) except (TypeError, ValueError): assert 0, '%r should be a TextAlignmentRole enum' % alignment mask = int(qt_api.QtCore.Qt.AlignHorizontal_Mask | qt_api.QtCore.Qt.AlignVertical_Mask) assert alignment == alignment & mask # Check that the "check state" is one we know about. state = self._model.data(self._model.index(0, 0), qt_api.QtCore.Qt.CheckStateRole) assert state in [None, qt_api.QtCore.Qt.Unchecked, qt_api.QtCore.Qt.PartiallyChecked, qt_api.QtCore.Qt.Checked]
def test_qvariant(tmpdir): """Test that make_variant and extract_from_variant work in the same way across all supported Qt bindings. """ settings = qt_api.QtCore.QSettings( str(tmpdir / "foo.ini"), qt_api.QtCore.QSettings.IniFormat ) settings.setValue("int", qt_api.make_variant(42)) settings.setValue("str", qt_api.make_variant("Hello")) settings.setValue("empty", qt_api.make_variant()) assert qt_api.extract_from_variant(settings.value("int")) == 42 assert qt_api.extract_from_variant(settings.value("str")) == "Hello" assert qt_api.extract_from_variant(settings.value("empty")) is None
def _on_rows_inserted(self, parent, start, end): """Confirm that what was said was going to happen actually did.""" c = self._insert.pop() last_data = self._model.data(self._model.index(start - 1, 0, parent)) next_data = self._model.data(self._model.index(end + 1, 0, c.parent)) expected_size = c.old_size + (end - start + 1) current_size = self._model.rowCount(parent) self._debug("rows inserted: start {}, end {}".format(start, end)) self._debug(" from rowsAboutToBeInserted: parent {}, " "size {} (-> {} expected), " "next data {!r}, last data {!r}".format( self._modelindex_debug(c.parent), c.old_size, expected_size, qt_api.extract_from_variant(c.next), qt_api.extract_from_variant(c.last) ) ) self._debug(" now in rowsInserted: parent {}, size {}, " "next data {!r}, last data {!r}".format( self._modelindex_debug(parent), current_size, qt_api.extract_from_variant(next_data), qt_api.extract_from_variant(last_data) ) ) if not qt_api.QtCore.qVersion().startswith('4.'): # Skipping this on Qt4 as the parent changes for some reason: # modeltest: rows about to be inserted: [...] # parent <invalid> (0x7f8f540eacf8), [...] # [...] # modeltest: from rowsAboutToBeInserted: # parent 0/0 None (0x7f8f540eacf8), [...] # modeltest: now in rowsInserted: # parent <invalid> (0x7f8f60a96cf8) [...] assert c.parent == parent for ii in range(start, end + 1): idx = self._model.index(ii, 0, parent) self._debug(" item {} inserted: {}".format(ii, self._modelindex_debug(idx))) self._debug('') assert current_size == expected_size assert c.last == last_data assert c.next == next_data
def _test_basic(self): """Try to call a number of the basic functions (not all). Make sure the model doesn't outright segfault, testing the functions which make sense. """ assert self._model.buddy(qt_api.QtCore.QModelIndex()) == qt_api.QtCore.QModelIndex() self._model.canFetchMore(qt_api.QtCore.QModelIndex()) assert self._column_count(qt_api.QtCore.QModelIndex()) >= 0 display_data = self._model.data(qt_api.QtCore.QModelIndex(), qt_api.QtCore.Qt.DisplayRole) assert qt_api.extract_from_variant(display_data) is None self._fetch_more(qt_api.QtCore.QModelIndex()) flags = self._model.flags(qt_api.QtCore.QModelIndex()) assert flags == qt_api.QtCore.Qt.ItemIsDropEnabled or not flags self._has_children(qt_api.QtCore.QModelIndex()) self._model.hasIndex(0, 0) self._model.headerData(0, qt_api.QtCore.Qt.Horizontal) self._model.index(0, 0) self._model.itemData(qt_api.QtCore.QModelIndex()) cache = None self._model.match(qt_api.QtCore.QModelIndex(), -1, cache) self._model.mimeTypes() assert self._parent(qt_api.QtCore.QModelIndex()) == qt_api.QtCore.QModelIndex() assert self._model.rowCount() >= 0 self._model.setData(qt_api.QtCore.QModelIndex(), None, -1) self._model.setHeaderData(-1, qt_api.QtCore.Qt.Horizontal, None) self._model.setHeaderData(999999, qt_api.QtCore.Qt.Horizontal, None) self._model.sibling(0, 0, qt_api.QtCore.QModelIndex()) self._model.span(qt_api.QtCore.QModelIndex()) self._model.supportedDropActions()
def _test_basic(self): """Try to call a number of the basic functions (not all). Make sure the model doesn't outright segfault, testing the functions which make sense. """ assert self._model.buddy( qt_api.QtCore.QModelIndex()) == qt_api.QtCore.QModelIndex() self._model.canFetchMore(qt_api.QtCore.QModelIndex()) assert self._column_count(qt_api.QtCore.QModelIndex()) >= 0 display_data = self._model.data(qt_api.QtCore.QModelIndex(), qt_api.QtCore.Qt.DisplayRole) assert qt_api.extract_from_variant(display_data) is None self._fetch_more(qt_api.QtCore.QModelIndex()) flags = self._model.flags(qt_api.QtCore.QModelIndex()) assert flags == qt_api.QtCore.Qt.ItemIsDropEnabled or not flags self._has_children(qt_api.QtCore.QModelIndex()) self._model.hasIndex(0, 0) self._model.headerData(0, qt_api.QtCore.Qt.Horizontal) self._model.index(0, 0) self._model.itemData(qt_api.QtCore.QModelIndex()) cache = None self._model.match(qt_api.QtCore.QModelIndex(), -1, cache) self._model.mimeTypes() assert self._parent( qt_api.QtCore.QModelIndex()) == qt_api.QtCore.QModelIndex() assert self._model.rowCount() >= 0 self._model.setData(qt_api.QtCore.QModelIndex(), None, -1) self._model.setHeaderData(-1, qt_api.QtCore.Qt.Horizontal, None) self._model.setHeaderData(999999, qt_api.QtCore.Qt.Horizontal, None) self._model.sibling(0, 0, qt_api.QtCore.QModelIndex()) self._model.span(qt_api.QtCore.QModelIndex()) self._model.supportedDropActions()
def _modelindex_debug(self, index): """Get a string for debug output for a QModelIndex.""" if not index.isValid(): return '<invalid> (0x{:x})'.format(id(index)) else: data = self._model.data(index, qt_api.QtCore.Qt.DisplayRole) return '{}/{} {!r} (0x{:x})'.format( index.row(), index.column(), qt_api.extract_from_variant(data), id(index))
def _on_rows_removed(self, parent, start, end): """Confirm that what was said was going to happen actually did.""" c = self._remove.pop() last_data = self._model.data(self._model.index(start - 1, 0, c.parent)) next_data = self._model.data(self._model.index(start, 0, c.parent)) current_size = self._model.rowCount(parent) expected_size = c.old_size - (end - start + 1) self._debug("rows removed: start {}, end {}".format(start, end)) self._debug(" from rowsAboutToBeRemoved: parent {}, " "size {} (-> {} expected), " "next data {!r}, last data {!r}".format( self._modelindex_debug(c.parent), c.old_size, expected_size, qt_api.extract_from_variant(c.next), qt_api.extract_from_variant(c.last) ) ) self._debug(" now in rowsRemoved: parent {}, size {}, " "next data {!r}, last data {!r}".format( self._modelindex_debug(parent), current_size, qt_api.extract_from_variant(next_data), qt_api.extract_from_variant(last_data) ) ) if not qt_api.QtCore.qVersion().startswith('4.'): # Skipping this on Qt4 as the parent changes for some reason # see _on_rows_inserted for details assert c.parent == parent assert current_size == expected_size assert c.last == last_data assert c.next == next_data
def _test_data(self): """Test model's implementation of data()""" if not self._has_children(): return # A valid index should have a valid QVariant data assert self._model.index(0, 0).isValid() string_types = [str] if sys.version_info.major == 2: string_types.append(unicode) # noqa if qt_api.QString is not None: string_types.append(qt_api.QString) string_types = tuple(string_types) types = [ (qt_api.QtCore.Qt.DisplayRole, string_types), (qt_api.QtCore.Qt.ToolTipRole, string_types), (qt_api.QtCore.Qt.StatusTipRole, string_types), (qt_api.QtCore.Qt.WhatsThisRole, string_types), (qt_api.QtCore.Qt.SizeHintRole, qt_api.QtCore.QSize), (qt_api.QtCore.Qt.FontRole, qt_api.QtGui.QFont), ( qt_api.QtCore.Qt.BackgroundColorRole, (qt_api.QtGui.QColor, qt_api.QtGui.QBrush), ), ( qt_api.QtCore.Qt.TextColorRole, (qt_api.QtGui.QColor, qt_api.QtGui.QBrush), ), ( qt_api.QtCore.Qt.DecorationRole, ( qt_api.QtGui.QPixmap, qt_api.QtGui.QImage, qt_api.QtGui.QIcon, qt_api.QtGui.QColor, qt_api.QtGui.QBrush, ), ), ] # General purpose roles with a fixed expected type for role, typ in types: data = self._model.data(self._model.index(0, 0), role) if data is not None: data = qt_api.extract_from_variant(data) assert data == None or isinstance(data, typ), role # noqa # Check that the alignment is one we know about alignment = self._model.data( self._model.index(0, 0), qt_api.QtCore.Qt.TextAlignmentRole ) alignment = qt_api.extract_from_variant(alignment) if alignment is not None: try: alignment = int(alignment) except (TypeError, ValueError): assert 0, "%r should be a TextAlignmentRole enum" % alignment mask = int( qt_api.QtCore.Qt.AlignHorizontal_Mask | qt_api.QtCore.Qt.AlignVertical_Mask ) assert alignment == alignment & mask # Check that the "check state" is one we know about. state = self._model.data( self._model.index(0, 0), qt_api.QtCore.Qt.CheckStateRole ) assert state in [ None, qt_api.QtCore.Qt.Unchecked, qt_api.QtCore.Qt.PartiallyChecked, qt_api.QtCore.Qt.Checked, ]
def _check_children(self, parent, current_depth=0): """Check parent/children relationships. Called from the parent() test. A model that returns an index of parent X should also return X when asking for the parent of the index. This recursive function does pretty extensive testing on the whole model in an effort to catch edge cases. This function assumes that rowCount(), columnCount() and index() already work. If they have a bug it will point it out, but the above tests should have already found the basic bugs because it is easier to figure out the problem in those tests then this one. """ # First just try walking back up the tree. p = parent while p.isValid(): p = p.parent() # For models that are dynamically populated if self._model.canFetchMore(parent): self._fetch_more(parent) rows = self._model.rowCount(parent) columns = self._column_count(parent) if rows > 0: assert self._has_children(parent) # Some further testing against rows(), columns(), and hasChildren() assert rows >= 0 assert columns >= 0 if rows > 0: assert self._has_children(parent) self._debug("Checking children of {} with depth {} " "({} rows, {} columns)".format( self._modelindex_debug(parent), current_depth, rows, columns)) top_left_child = self._model.index(0, 0, parent) assert not self._model.hasIndex(rows + 1, 0, parent) for r in range(rows): if self._model.canFetchMore(parent): self._fetch_more(parent) assert not self._model.hasIndex(r, columns + 1, parent) for c in range(columns): assert self._model.hasIndex(r, c, parent) index = self._model.index(r, c, parent) # rowCount() and columnCount() said that it existed... assert index.isValid() # index() should always return the same index when called twice # in a row modified_index = self._model.index(r, c, parent) assert index == modified_index # Make sure we get the same index if we request it twice in a # row a = self._model.index(r, c, parent) b = self._model.index(r, c, parent) assert a == b sibling = self._model.sibling(r, c, top_left_child) assert index == sibling sibling = top_left_child.sibling(r, c) assert index == sibling # Some basic checking on the index that is returned assert index.model() == self._model assert index.row() == r assert index.column() == c data = self._model.data(index, qt_api.QtCore.Qt.DisplayRole) if not self.data_display_may_return_none: assert qt_api.extract_from_variant(data) is not None # If the next test fails here is some somewhat useful debug you # play with. if self._parent(index) != parent: self._debug( "parent-check failed for index {}:\n" " parent {} != expected {}".format( self._modelindex_debug(index), self._modelindex_debug(self._parent(index)), self._modelindex_debug(parent) ) ) # Check that we can get back our real parent. assert self._parent(index) == parent # recursively go down the children if self._has_children(index) and current_depth < 10: self._debug("{} has {} children".format( self._modelindex_debug(index), self._model.rowCount(index) )) self._check_children(index, current_depth + 1) # make sure that after testing the children that the index # doesn't change. newer_index = self._model.index(r, c, parent) assert index == newer_index self._debug("Children check for {} done".format(self._modelindex_debug(parent)))
def _check_children(self, parent, current_depth=0): """Check parent/children relationships. Called from the parent() test. A model that returns an index of parent X should also return X when asking for the parent of the index. This recursive function does pretty extensive testing on the whole model in an effort to catch edge cases. This function assumes that rowCount(), columnCount() and index() already work. If they have a bug it will point it out, but the above tests should have already found the basic bugs because it is easier to figure out the problem in those tests then this one. """ # First just try walking back up the tree. p = parent while p.isValid(): p = p.parent() # For models that are dynamically populated if self._model.canFetchMore(parent): self._fetch_more(parent) rows = self._model.rowCount(parent) columns = self._column_count(parent) if rows > 0: assert self._has_children(parent) # Some further testing against rows(), columns(), and hasChildren() assert rows >= 0 assert columns >= 0 if rows > 0: assert self._has_children(parent) self._debug("Checking children of {} with depth {} " "({} rows, {} columns)".format( self._modelindex_debug(parent), current_depth, rows, columns)) top_left_child = self._model.index(0, 0, parent) assert not self._model.hasIndex(rows + 1, 0, parent) for r in range(rows): if self._model.canFetchMore(parent): self._fetch_more(parent) assert not self._model.hasIndex(r, columns + 1, parent) for c in range(columns): assert self._model.hasIndex(r, c, parent) index = self._model.index(r, c, parent) # rowCount() and columnCount() said that it existed... assert index.isValid() # index() should always return the same index when called twice # in a row modified_index = self._model.index(r, c, parent) assert index == modified_index # Make sure we get the same index if we request it twice in a # row a = self._model.index(r, c, parent) b = self._model.index(r, c, parent) assert a == b sibling = self._model.sibling(r, c, top_left_child) assert index == sibling sibling = top_left_child.sibling(r, c) assert index == sibling # Some basic checking on the index that is returned assert index.model() == self._model assert index.row() == r assert index.column() == c data = self._model.data(index, qt_api.QtCore.Qt.DisplayRole) if not self.data_display_may_return_none: assert qt_api.extract_from_variant(data) is not None # If the next test fails here is some somewhat useful debug you # play with. if self._parent(index) != parent: self._debug("parent-check failed for index {}:\n" " parent {} != expected {}".format( self._modelindex_debug(index), self._modelindex_debug( self._parent(index)), self._modelindex_debug(parent))) # Check that we can get back our real parent. assert self._parent(index) == parent # recursively go down the children if self._has_children(index) and current_depth < 10: self._debug("{} has {} children".format( self._modelindex_debug(index), self._model.rowCount(index))) self._check_children(index, current_depth + 1) # make sure that after testing the children that the index # doesn't change. newer_index = self._model.index(r, c, parent) assert index == newer_index self._debug("Children check for {} done".format( self._modelindex_debug(parent)))