1# -*- coding: utf-8 -*- 2"""QGIS Unit tests for the attribute form 3 4 5Run with ctest -V -R PyQgsAttributeForm 6 7.. note:: This program is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2 of the License, or 10(at your option) any later version. 11 12""" 13__author__ = 'Alessandro Pasotti' 14__date__ = '2019-06-06' 15__copyright__ = 'Copyright 2019, The QGIS Project' 16 17from qgis.testing import start_app, unittest 18from qgis.core import ( 19 QgsFields, 20 QgsVectorLayer, 21 QgsFeature, 22 QgsEditorWidgetSetup, 23 QgsEditFormConfig, 24 QgsAttributeEditorElement, 25) 26from qgis.gui import ( 27 QgsAttributeForm, 28 QgsGui, 29 QgsEditorWidgetWrapper, 30 QgsMapCanvas 31) 32 33QGISAPP = start_app() 34 35 36class TestQgsAttributeForm(unittest.TestCase): 37 38 @classmethod 39 def setUpClass(cls): 40 cls.mCanvas = QgsMapCanvas() 41 QgsGui.editorWidgetRegistry().initEditors(cls.mCanvas) 42 43 @classmethod 44 def createLayerWithOnePoint(cls, field_type): 45 layer = QgsVectorLayer("Point?field=fld:%s" % field_type, 46 "vl", "memory") 47 pr = layer.dataProvider() 48 f = QgsFeature() 49 assert pr.addFeatures([f]) 50 assert layer.featureCount() == 1 51 return layer 52 53 @classmethod 54 def createFormWithDuplicateWidget(cls, vl, field_type, widget_type): 55 """Creates a form with two identical widgets for the same field""" 56 57 config = vl.editFormConfig() 58 config.setLayout(QgsEditFormConfig.TabLayout) 59 element = config.tabs()[0] 60 element2 = element.clone(element) 61 config.addTab(element2) 62 vl.setEditFormConfig(config) 63 vl.setEditorWidgetSetup(0, QgsEditorWidgetSetup(widget_type, {})) 64 form = QgsAttributeForm(vl, next(vl.getFeatures())) 65 assert (form.editable()) 66 return form 67 68 @classmethod 69 def get_widgets_for_field(cls, vl): 70 """Get compatible widget names""" 71 72 return [k for k, v in QgsGui.editorWidgetRegistry().factories().items() if v.supportsField(vl, 0)] 73 74 @classmethod 75 def checkForm(cls, field_type, value): 76 """Creates a vector layer and an associated form with two identical widgets for the same field and test it with NULL and after setting a value 77 """ 78 79 vl = cls.createLayerWithOnePoint(field_type) 80 assert (vl.startEditing()) 81 for widget_type in cls.get_widgets_for_field(vl): 82 form = cls.createFormWithDuplicateWidget(vl, field_type, widget_type) 83 vl.changeAttributeValue(1, 0, value) 84 form.setFeature(next(vl.getFeatures())) 85 86 def test_duplicated_widgets(self): 87 """ 88 Note: this crashed two times for datetime (see GH #29937): 89 90 - first crash with initial NULL values, because widget's clear() triggered changed() 91 - second crash when setting a value, because setDateTime() triggered changed() 92 93 There are no assertions in this test because we are looking for a crash. 94 """ 95 96 field_types = { 97 'integer': 123, 98 'double': 123.45, 99 'string': 'lorem ipsum', 100 'date': '2019-01-01', 101 'time': '12:12:12', 102 'datetime': '2019-01-01', 103 'int2': 123, 104 'int4': 123, 105 'int8': 123, 106 'numeric': 123.45, 107 'decimal': 123.45, 108 'real': 123.45, 109 'double precision': 123.45, 110 'text': 'lorem ipsum', 111 'bool': True, 112 # 'binary' 113 } 114 115 for field_type, value in field_types.items(): 116 self.checkForm(field_type, value) 117 118 119if __name__ == '__main__': 120 unittest.main() 121