Skip to content

Commit 3d7ac65

Browse files
committedOct 9, 2017
Add tests
1 parent 3f8ae8b commit 3d7ac65

File tree

3 files changed

+393
-0
lines changed

3 files changed

+393
-0
lines changed
 

‎tests/src/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ ADD_PYTHON_TEST(PyQgsZipUtils test_qgsziputils.py)
186186
ADD_PYTHON_TEST(PyQgsSourceSelectProvider test_qgssourceselectprovider.py)
187187
ADD_PYTHON_TEST(PyQgsAuthManagerProxy test_authmanager_proxy.py)
188188
ADD_PYTHON_TEST(PyQgsAuthSettingsWidget test_authsettingswidget.py)
189+
ADD_PYTHON_TEST(PyQgsAuxiliaryStorage test_qgsauxiliarystorage.py)
189190

190191
IF (NOT WIN32)
191192
ADD_PYTHON_TEST(PyQgsLogger test_qgslogger.py)
Lines changed: 390 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,390 @@
1+
# -*- coding: utf-8 -*-
2+
"""QGIS Unit tests for Auxiliary Storage.
3+
4+
.. note:: This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation; either version 2 of the License, or
7+
(at your option) any later version.
8+
"""
9+
__author__ = 'Paul Blottiere'
10+
__date__ = '06/09/2017'
11+
__copyright__ = 'Copyright 2017, The QGIS Project'
12+
# This will get replaced with a git SHA1 when you do a git archive
13+
__revision__ = '$Format:%H$'
14+
15+
import qgis # NOQA
16+
17+
import os
18+
19+
from qgis.PyQt.QtCore import QTemporaryFile
20+
from qgis.core import (QgsAuxiliaryStorage,
21+
QgsAuxiliaryLayer,
22+
QgsVectorLayer,
23+
QgsFeature,
24+
QgsGeometry,
25+
QgsPropertyDefinition,
26+
QgsProject,
27+
QgsFeatureRequest,
28+
QgsPalLayerSettings,
29+
QgsSymbolLayer,
30+
QgsVectorLayerSimpleLabeling,
31+
NULL)
32+
from qgis.testing import start_app, unittest
33+
from utilities import unitTestDataPath, writeShape
34+
start_app()
35+
36+
37+
def tmpPath():
38+
f = QTemporaryFile()
39+
f.open()
40+
f.close()
41+
os.remove(f.fileName())
42+
43+
return f.fileName()
44+
45+
46+
def createLayer():
47+
vl = QgsVectorLayer(
48+
'Point?crs=epsg:4326&field=pk:integer&field=cnt:integer&field=name:string(0)&field=name2:string(0)&field=num_char:string&key=pk', 'test', 'memory')
49+
assert (vl.isValid())
50+
51+
f1 = QgsFeature()
52+
f1.setAttributes([5, -200, NULL, 'NuLl', '5'])
53+
f1.setGeometry(QgsGeometry.fromWkt('Point (-71.123 78.23)'))
54+
55+
f2 = QgsFeature()
56+
f2.setAttributes([3, 300, 'Pear', 'PEaR', '3'])
57+
58+
f3 = QgsFeature()
59+
f3.setAttributes([1, 100, 'Orange', 'oranGe', '1'])
60+
f3.setGeometry(QgsGeometry.fromWkt('Point (-70.332 66.33)'))
61+
62+
f4 = QgsFeature()
63+
f4.setAttributes([2, 200, 'Apple', 'Apple', '2'])
64+
f4.setGeometry(QgsGeometry.fromWkt('Point (-68.2 70.8)'))
65+
66+
f5 = QgsFeature()
67+
f5.setAttributes([4, 400, 'Honey', 'Honey', '4'])
68+
f5.setGeometry(QgsGeometry.fromWkt('Point (-65.32 78.3)'))
69+
70+
vl.dataProvider().addFeatures([f1, f2, f3, f4, f5])
71+
return vl
72+
73+
74+
class TestQgsAuxiliaryStorage(unittest.TestCase):
75+
76+
def testCreateSaveOpenStorageWithString(self):
77+
# Empty string in copy mode. A new database is created in a temporary
78+
# file.
79+
s0 = QgsAuxiliaryStorage()
80+
self.assertTrue(s0.isValid())
81+
82+
# saveAs should be used instead of save in case of an empty string
83+
# given to the constructor of QgsAuxiliaryStorage
84+
self.assertEqual(s0.fileName(), "")
85+
self.assertFalse(s0.save())
86+
87+
# Create a new auxiliary layer with 'pk' as key
88+
vl0 = createLayer()
89+
pkf = vl0.fields().field(vl0.fields().indexOf('pk'))
90+
al0 = s0.createAuxiliaryLayer(pkf, vl0)
91+
self.assertTrue(al0.isValid())
92+
93+
# Test the auxiliary key
94+
key = al0.joinInfo().targetFieldName()
95+
self.assertEqual(key, 'pk')
96+
97+
# Add a field in auxiliary layer
98+
p = QgsPropertyDefinition('propName', QgsPropertyDefinition.DataTypeNumeric, '', '', 'user')
99+
self.assertTrue(al0.addAuxiliaryField(p))
100+
101+
# saveAs without saving the auxiliary layer, the auxiliary field is lost
102+
f = tmpPath()
103+
self.assertTrue(s0.saveAs(f))
104+
105+
# Open the previous database.
106+
s1 = QgsAuxiliaryStorage(f)
107+
self.assertTrue(s1.isValid())
108+
109+
# Load the auxiliary layer from auxiliary storage
110+
self.assertTrue(vl0.loadAuxiliaryLayer(s1, key))
111+
112+
# As the vl0 has not been saved before saving the storage, there
113+
# shouldn't have auxiliary fields
114+
self.assertEqual(len(vl0.auxiliaryLayer().auxiliaryFields()), 0)
115+
116+
# Save the layer before saving the storage
117+
self.assertTrue(al0.save())
118+
self.assertTrue(s0.saveAs(f))
119+
120+
# Open the previous database.
121+
s2 = QgsAuxiliaryStorage(f)
122+
self.assertTrue(s2.isValid())
123+
124+
# Load the auxiliary layer from auxiliary storage
125+
self.assertTrue(vl0.loadAuxiliaryLayer(s2, key))
126+
127+
# As the vl0 has been saved before saving the storage, there
128+
# should have 1 auxiliary field
129+
self.assertEqual(len(vl0.auxiliaryLayer().auxiliaryFields()), 1)
130+
131+
# save is available on s2
132+
self.assertTrue(s2.save())
133+
134+
def testCreateSaveOpenStorageWithProject(self):
135+
# New project without fileName
136+
p = QgsProject()
137+
138+
# Create storage
139+
s0 = QgsAuxiliaryStorage(p)
140+
self.assertTrue(s0.isValid())
141+
142+
# saveAs should be used instead of save in case of an empty string
143+
# given to the constructor of QgsAuxiliaryStorage
144+
self.assertEqual(s0.fileName(), "")
145+
self.assertFalse(s0.save())
146+
147+
# saveAs
148+
f = tmpPath()
149+
self.assertTrue(s0.saveAs(f))
150+
151+
def testProjectStorage(self):
152+
# New project without fileName
153+
p0 = QgsProject()
154+
self.assertTrue(p0.auxiliaryStorage().isValid())
155+
156+
# Create new layers with key otherwise auxiliary layers are not
157+
# automacially created when added in project
158+
vl0 = createLayer()
159+
vl0Shp = writeShape(vl0, 'vl0.shp')
160+
161+
vl1 = createLayer()
162+
vl1Shp = writeShape(vl1, 'vl1.shp')
163+
164+
vl0 = QgsVectorLayer(vl0Shp, 'points', 'ogr')
165+
self.assertTrue(vl0.isValid())
166+
167+
vl1 = QgsVectorLayer(vl1Shp, 'points', 'ogr')
168+
self.assertTrue(vl1.isValid())
169+
170+
# Add layers to project and check underlying auxiliary layers
171+
p0.addMapLayers([vl0, vl1])
172+
173+
self.assertTrue(vl0.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'pk'))
174+
self.assertTrue(vl1.loadAuxiliaryLayer(p0.auxiliaryStorage(), 'num_char'))
175+
176+
al0 = vl0.auxiliaryLayer()
177+
al1 = vl1.auxiliaryLayer()
178+
179+
self.assertEqual(al0.joinInfo().targetFieldName(), 'pk')
180+
self.assertEqual(al1.joinInfo().targetFieldName(), 'num_char')
181+
182+
# Add a field in auxiliary layers
183+
pdef0 = QgsPropertyDefinition('propname', QgsPropertyDefinition.DataTypeNumeric, '', '', 'ut')
184+
self.assertTrue(al0.addAuxiliaryField(pdef0))
185+
186+
pdef1 = QgsPropertyDefinition('propname1', QgsPropertyDefinition.DataTypeString, '', '', 'ut')
187+
self.assertTrue(al1.addAuxiliaryField(pdef1))
188+
189+
# Check auxiliary fields names
190+
af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, False)
191+
self.assertEqual(af0Name, 'ut_propname')
192+
af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, False)
193+
self.assertEqual(af1Name, 'ut_propname1')
194+
195+
# Set value for auxiliary fields
196+
req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
197+
f = QgsFeature()
198+
vl0.getFeatures(req).nextFeature(f)
199+
self.assertTrue(f.isValid())
200+
af0Name = QgsAuxiliaryLayer.nameFromProperty(pdef0, True)
201+
index0 = vl0.fields().indexOf(af0Name)
202+
vl0.changeAttributeValue(f.id(), index0, 333)
203+
204+
req = QgsFeatureRequest().setFilterExpression("name = 'Apple'")
205+
f = QgsFeature()
206+
vl1.getFeatures(req).nextFeature(f)
207+
self.assertTrue(f.isValid())
208+
af1Name = QgsAuxiliaryLayer.nameFromProperty(pdef1, True)
209+
index1 = vl1.fields().indexOf(af1Name)
210+
vl1.changeAttributeValue(f.id(), index0, 'myvalue')
211+
212+
req = QgsFeatureRequest().setFilterExpression("name = 'Orange'")
213+
f = QgsFeature()
214+
vl1.getFeatures(req).nextFeature(f)
215+
self.assertTrue(f.isValid())
216+
vl1.changeAttributeValue(f.id(), index0, 'myvalue1')
217+
218+
# Save the project in a zip file
219+
f = tmpPath() + '.qgz'
220+
p0.write(f)
221+
222+
# Open the zip file with embedded auxiliary storage
223+
p1 = QgsProject()
224+
p1.read(f)
225+
226+
# Check that auxiliary fields are well loaded in layers
227+
self.assertEqual(len(p1.mapLayers().values()), 2)
228+
229+
for vl in p1.mapLayers().values():
230+
al = vl.auxiliaryLayer()
231+
self.assertEqual(len(al.auxiliaryFields()), 1)
232+
233+
af = al.auxiliaryFields()[0]
234+
afPropDef = QgsAuxiliaryLayer.propertyDefinitionFromField(af)
235+
self.assertEqual(afPropDef.origin(), 'ut')
236+
237+
if vl.auxiliaryLayer().joinInfo().targetFieldName() == 'pk':
238+
self.assertEqual(afPropDef.name(), 'propname')
239+
self.assertEqual(al.featureCount(), 1)
240+
241+
req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
242+
f = QgsFeature()
243+
vl.getFeatures(req).nextFeature(f)
244+
self.assertTrue(f.isValid())
245+
self.assertEqual(f.attributes()[index0], 333.0)
246+
else: # num_char
247+
self.assertEqual(al.featureCount(), 2)
248+
self.assertEqual(afPropDef.name(), 'propname1')
249+
250+
req = QgsFeatureRequest().setFilterExpression("name = 'Apple'")
251+
f = QgsFeature()
252+
vl.getFeatures(req).nextFeature(f)
253+
self.assertTrue(f.isValid())
254+
self.assertEqual(f.attributes()[index1], 'myvalue')
255+
256+
req = QgsFeatureRequest().setFilterExpression("name = 'Orange'")
257+
f = QgsFeature()
258+
vl.getFeatures(req).nextFeature(f)
259+
self.assertTrue(f.isValid())
260+
self.assertEqual(f.attributes()[index1], 'myvalue1')
261+
262+
def testAuxiliaryFieldWidgets(self):
263+
# Init storage
264+
s = QgsAuxiliaryStorage()
265+
self.assertTrue(s.isValid())
266+
267+
# Create a new auxiliary layer with 'pk' as key
268+
vl = createLayer()
269+
pkf = vl.fields().field(vl.fields().indexOf('pk'))
270+
al = s.createAuxiliaryLayer(pkf, vl)
271+
self.assertTrue(al.isValid())
272+
273+
# Set the auxiliary layer to the vector layer
274+
vl.setAuxiliaryLayer(al)
275+
276+
# Add a visible property
277+
p = QgsPropertyDefinition('propName', QgsPropertyDefinition.DataTypeNumeric, '', '', 'user')
278+
self.assertTrue(al.addAuxiliaryField(p))
279+
280+
index = al.indexOfPropertyDefinition(p)
281+
self.assertFalse(al.isHiddenProperty(index))
282+
283+
afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
284+
index = vl.fields().indexOf(afName)
285+
setup = vl.editorWidgetSetup(index)
286+
self.assertEqual(setup.type(), '')
287+
288+
tested = False
289+
for c in vl.attributeTableConfig().columns():
290+
if c.name == afName:
291+
self.assertFalse(c.hidden)
292+
tested = True
293+
break
294+
self.assertTrue(tested)
295+
296+
# Add a hidden property
297+
p = QgsPalLayerSettings.propertyDefinitions()[QgsPalLayerSettings.PositionX]
298+
self.assertTrue(al.addAuxiliaryField(p))
299+
300+
index = al.indexOfPropertyDefinition(p)
301+
self.assertTrue(al.isHiddenProperty(index))
302+
303+
afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
304+
index = vl.fields().indexOf(afName)
305+
setup = vl.editorWidgetSetup(index)
306+
self.assertEqual(setup.type(), 'Hidden')
307+
308+
tested = False
309+
for c in vl.attributeTableConfig().columns():
310+
if c.name == afName:
311+
self.assertTrue(c.hidden)
312+
tested = True
313+
break
314+
self.assertTrue(tested)
315+
316+
# Add a color property
317+
p = QgsSymbolLayer.propertyDefinitions()[QgsSymbolLayer.PropertyFillColor]
318+
self.assertTrue(al.addAuxiliaryField(p))
319+
320+
index = al.indexOfPropertyDefinition(p)
321+
self.assertFalse(al.isHiddenProperty(index))
322+
323+
afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
324+
index = vl.fields().indexOf(afName)
325+
setup = vl.editorWidgetSetup(index)
326+
self.assertEqual(setup.type(), 'Color')
327+
328+
def testClear(self):
329+
s = QgsAuxiliaryStorage()
330+
self.assertTrue(s.isValid())
331+
332+
# Create a new auxiliary layer with 'pk' as key
333+
vl = createLayer()
334+
pkf = vl.fields().field(vl.fields().indexOf('pk'))
335+
al = s.createAuxiliaryLayer(pkf, vl)
336+
self.assertTrue(al.isValid())
337+
vl.setAuxiliaryLayer(al)
338+
339+
# Add a field in auxiliary layer
340+
p = QgsPropertyDefinition('myprop', QgsPropertyDefinition.DataTypeNumeric, '', '', 'me')
341+
self.assertFalse(al.exists(p))
342+
self.assertTrue(al.addAuxiliaryField(p))
343+
self.assertTrue(al.exists(p))
344+
345+
# Count auxiliary features
346+
self.assertEqual(al.featureCount(), 0)
347+
348+
# Set value for auxiliary fields
349+
req = QgsFeatureRequest().setFilterExpression("name = 'Honey'")
350+
f = QgsFeature()
351+
vl.getFeatures(req).nextFeature(f)
352+
self.assertTrue(f.isValid())
353+
afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
354+
index = vl.fields().indexOf(afName)
355+
vl.changeAttributeValue(f.id(), index, 333)
356+
357+
# Count auxiliary features
358+
self.assertEqual(al.featureCount(), 1)
359+
360+
# Clear and count
361+
al.clear()
362+
self.assertEqual(al.featureCount(), 0)
363+
364+
def testCreateProperty(self):
365+
s = QgsAuxiliaryStorage()
366+
self.assertTrue(s.isValid())
367+
368+
# Create a new auxiliary layer with 'pk' as key
369+
vl = createLayer()
370+
pkf = vl.fields().field(vl.fields().indexOf('pk'))
371+
al = s.createAuxiliaryLayer(pkf, vl)
372+
self.assertTrue(al.isValid())
373+
vl.setAuxiliaryLayer(al)
374+
375+
# Create a new labeling property on layer without labels
376+
key = QgsPalLayerSettings.PositionX
377+
index = QgsAuxiliaryLayer.createProperty(key, vl)
378+
self.assertEqual(index, -1)
379+
380+
vl.setLabeling(QgsVectorLayerSimpleLabeling(QgsPalLayerSettings()))
381+
index = QgsAuxiliaryLayer.createProperty(key, vl)
382+
383+
p = QgsPalLayerSettings.propertyDefinitions()[key]
384+
afName = QgsAuxiliaryLayer.nameFromProperty(p, True)
385+
afIndex = vl.fields().indexOf(afName)
386+
self.assertEqual(index, afIndex)
387+
388+
389+
if __name__ == '__main__':
390+
unittest.main()

‎tests/src/python/utilities.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ def writeShape(theMemoryLayer, theFileName):
123123
mySkipAttributesFlag)
124124
assert myResult == QgsVectorFileWriter.NoError, 'Writing shape failed, Error {} ({})'.format(myResult, myErrorMessage)
125125

126+
return myFileName
127+
126128

127129
def doubleNear(a, b, tol=0.0000000001):
128130
"""

0 commit comments

Comments
 (0)
Please sign in to comment.