Skip to content

Commit 0c72d4b

Browse files
committed
Add unit tests
1 parent e2ee153 commit 0c72d4b

6 files changed

+377
-1
lines changed

tests/src/python/test_qgssymbollayer_readsld.py

Lines changed: 293 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,23 @@
2626
import qgis # NOQA
2727

2828
import os
29+
from qgis.PyQt.QtXml import QDomDocument
2930
from qgis.testing import start_app, unittest
3031
from qgis.core import (QgsVectorLayer,
3132
QgsFeature,
3233
QgsGeometry,
33-
QgsPoint
34+
QgsUnitTypes,
35+
QgsPoint,
36+
QgsSvgMarkerSymbolLayer,
37+
QgsEllipseSymbolLayer,
38+
QgsSimpleFillSymbolLayer,
39+
QgsSVGFillSymbolLayer,
40+
QgsSvgMarkerSymbolLayer,
41+
QgsLinePatternFillSymbolLayer,
42+
QgsSimpleLineSymbolLayer,
43+
QgsMarkerLineSymbolLayer,
44+
QgsSimpleMarkerSymbolLayer,
45+
QgsFontMarkerSymbolLayer
3446
)
3547
from qgis.testing.mocked import get_iface
3648
from utilities import unitTestDataPath
@@ -51,6 +63,28 @@ def createLayerWithOneLine():
5163
return linelayer
5264

5365

66+
def createLayerWithOnePoint():
67+
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
68+
"addfeat", "memory")
69+
pr = layer.dataProvider()
70+
f = QgsFeature()
71+
f.setAttributes(["test", 123])
72+
f.setGeometry(QgsGeometry.fromPoint(QgsPoint(100, 200)))
73+
assert pr.addFeatures([f])
74+
assert layer.pendingFeatureCount() == 1
75+
return layer
76+
77+
78+
def createLayerWithOnePolygon():
79+
layer = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int", "vl", "memory")
80+
assert layer.isValid()
81+
f1 = QgsFeature(layer.dataProvider().fields(), 1)
82+
f1.setAttribute("pk", 1)
83+
f1.setGeometry(QgsGeometry.fromPolygon([[QgsPoint(2484588, 2425722), QgsPoint(2482767, 2398853), QgsPoint(2520109, 2397715), QgsPoint(2520792, 2425494), QgsPoint(2484588, 2425722)]]))
84+
assert layer.dataProvider().addFeatures([f1])
85+
return layer
86+
87+
5488
class TestQgsSymbolLayerReadSld(unittest.TestCase):
5589

5690
"""
@@ -111,6 +145,264 @@ def testSimpleMarkerRotation(self):
111145
props = layer.renderer().symbol().symbolLayers()[0].properties()
112146
self.assertEqual(props['angle'], '50')
113147

148+
def testSymbolSizeUom(self):
149+
# create a layer
150+
layer = createLayerWithOnePoint()
151+
152+
# load a sld with marker size without uom attribute (pixels)
153+
sld = 'symbol_layer/QgsSvgMarkerSymbolLayer.sld'
154+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
155+
layer.loadSldStyle(mFilePath)
156+
157+
sld_size_px = 12
158+
159+
sl = layer.renderer().symbol().symbolLayers()[0]
160+
size = sl.size()
161+
unit = sl.outputUnit()
162+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
163+
self.assertEqual(size, sld_size_px)
164+
165+
# load a sld with marker size with uom attribute in pixel
166+
sld = 'symbol_layer/QgsSvgMarkerSymbolLayerUomPixel.sld'
167+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
168+
layer.loadSldStyle(mFilePath)
169+
170+
sld_size_px = 12
171+
172+
sl = layer.renderer().symbol().symbolLayers()[0]
173+
size = sl.size()
174+
unit = sl.outputUnit()
175+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
176+
self.assertEqual(size, sld_size_px)
177+
178+
# load a sld with marker size with uom attribute in meter
179+
sld = 'symbol_layer/QgsSvgMarkerSymbolLayerUomMetre.sld'
180+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
181+
layer.loadSldStyle(mFilePath)
182+
183+
sld_size_px = 12 / (0.28 * 0.001)
184+
185+
sl = layer.renderer().symbol().symbolLayers()[0]
186+
size = sl.size()
187+
unit = sl.outputUnit()
188+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
189+
self.assertAlmostEqual(size, sld_size_px, delta=0.1)
190+
191+
# load a sld with marker size with uom attribute in foot
192+
sld = 'symbol_layer/QgsSvgMarkerSymbolLayerUomFoot.sld'
193+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
194+
layer.loadSldStyle(mFilePath)
195+
196+
sld_size_px = 12 * (304.8 / 0.28)
197+
198+
sl = layer.renderer().symbol().symbolLayers()[0]
199+
size = sl.size()
200+
unit = sl.outputUnit()
201+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
202+
self.assertAlmostEqual(size, sld_size_px, delta=0.1)
203+
204+
def testSymbolSize(self):
205+
# create a layers
206+
layer = createLayerWithOnePoint()
207+
player = createLayerWithOnePolygon()
208+
209+
# size test for QgsEllipseSymbolLayer
210+
sld = 'symbol_layer/QgsEllipseSymbolLayer.sld'
211+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
212+
layer.loadSldStyle(mFilePath)
213+
214+
sld_size_px = 7
215+
sld_stroke_width_px = 1
216+
217+
sl = layer.renderer().symbol().symbolLayers()[0]
218+
size = sl.symbolWidth()
219+
stroke_width = sl.strokeWidth()
220+
unit = sl.outputUnit()
221+
self.assertTrue(isinstance(sl, QgsEllipseSymbolLayer))
222+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
223+
self.assertEqual(size, sld_size_px)
224+
self.assertEqual(stroke_width, sld_stroke_width_px)
225+
226+
# size test for QgsVectorFieldSymbolLayer
227+
# createFromSld not implemented
228+
229+
# size test for QgsSimpleFillSymbolLayer
230+
sld = 'symbol_layer/QgsSimpleFillSymbolLayer.sld'
231+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
232+
player.loadSldStyle(mFilePath)
233+
234+
sld_stroke_width_px = 0.26
235+
236+
sl = player.renderer().symbol().symbolLayers()[0]
237+
stroke_width = sl.strokeWidth()
238+
unit = sl.outputUnit()
239+
self.assertTrue(isinstance(sl, QgsSimpleFillSymbolLayer))
240+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
241+
self.assertEqual(stroke_width, sld_stroke_width_px)
242+
243+
# size test for QgsSVGFillSymbolLayer
244+
sld = 'symbol_layer/QgsSVGFillSymbolLayer.sld'
245+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
246+
player.loadSldStyle(mFilePath)
247+
248+
sld_size_px = 6
249+
sld_stroke_width_px = 3
250+
251+
sl = player.renderer().symbol().symbolLayers()[0]
252+
size = sl.patternWidth()
253+
stroke_width = sl.svgStrokeWidth()
254+
unit = sl.outputUnit()
255+
self.assertTrue(isinstance(sl, QgsSVGFillSymbolLayer))
256+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
257+
self.assertEqual(size, sld_size_px)
258+
self.assertEqual(stroke_width, sld_stroke_width_px)
259+
260+
# size test for QgsSvgMarkerSymbolLayer
261+
sld = 'symbol_layer/QgsSvgMarkerSymbolLayer.sld'
262+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
263+
layer.loadSldStyle(mFilePath)
264+
265+
sld_size_px = 12
266+
267+
sl = layer.renderer().symbol().symbolLayers()[0]
268+
size = sl.size()
269+
unit = sl.outputUnit()
270+
self.assertTrue(isinstance(sl, QgsSvgMarkerSymbolLayer))
271+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
272+
self.assertEqual(size, sld_size_px)
273+
274+
# size test for QgsPointPatternFillSymbolLayer
275+
# createFromSld not implemented
276+
277+
# size test for QgsLinePatternFillSymbolLayer
278+
sld = 'symbol_layer/QgsLinePatternFillSymbolLayer.sld'
279+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
280+
player.loadSldStyle(mFilePath)
281+
282+
sld_size_px = 4
283+
sld_stroke_width_px = 1.5
284+
285+
sl = player.renderer().symbol().symbolLayers()[0]
286+
size = sl.distance()
287+
stroke_width = sl.lineWidth()
288+
unit = sl.outputUnit()
289+
self.assertTrue(isinstance(sl, QgsLinePatternFillSymbolLayer))
290+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
291+
self.assertEqual(size, sld_size_px)
292+
self.assertEqual(stroke_width, sld_stroke_width_px)
293+
294+
# test size for QgsSimpleLineSymbolLayer
295+
sld = 'symbol_layer/QgsSimpleLineSymbolLayer.sld'
296+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
297+
player.loadSldStyle(mFilePath)
298+
299+
sld_stroke_width_px = 1.26
300+
301+
sl = player.renderer().symbol().symbolLayers()[0]
302+
stroke_width = sl.width()
303+
unit = sl.outputUnit()
304+
self.assertTrue(isinstance(sl, QgsSimpleLineSymbolLayer))
305+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
306+
self.assertEqual(stroke_width, sld_stroke_width_px)
307+
308+
# test size for QgsMarkerLineSymbolLayer
309+
sld = 'symbol_layer/QgsMarkerLineSymbolLayer.sld'
310+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
311+
player.loadSldStyle(mFilePath)
312+
313+
sld_interval_px = 3.3
314+
sld_offset_px = 6.6
315+
316+
sl = player.renderer().symbol().symbolLayers()[0]
317+
interval = sl.interval()
318+
offset = sl.offset()
319+
unit = sl.outputUnit()
320+
self.assertTrue(isinstance(sl, QgsMarkerLineSymbolLayer))
321+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
322+
self.assertEqual(interval, sld_interval_px)
323+
self.assertEqual(offset, sld_offset_px)
324+
325+
# test size for QgsSimpleMarkerSymbolLayer
326+
sld = 'symbol_layer/QgsSimpleMarkerSymbolLayer.sld'
327+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
328+
layer.loadSldStyle(mFilePath)
329+
330+
sld_size_px = 6
331+
sld_displacement_x_px = 3.3
332+
sld_displacement_y_px = 6.6
333+
334+
sl = layer.renderer().symbol().symbolLayers()[0]
335+
size = sl.size()
336+
offset = sl.offset()
337+
unit = sl.outputUnit()
338+
self.assertTrue(isinstance(sl, QgsSimpleMarkerSymbolLayer))
339+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
340+
self.assertEqual(size, sld_size_px)
341+
self.assertEqual(offset.x(), sld_displacement_x_px)
342+
self.assertEqual(offset.y(), sld_displacement_y_px)
343+
344+
# test size for QgsSVGMarkerSymbolLayer
345+
sld = 'symbol_layer/QgsSvgMarkerSymbolLayer.sld'
346+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
347+
layer.loadSldStyle(mFilePath)
348+
349+
sld_size_px = 12
350+
351+
sl = layer.renderer().symbol().symbolLayers()[0]
352+
size = sl.size()
353+
self.assertTrue(isinstance(sl, QgsSvgMarkerSymbolLayer))
354+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
355+
self.assertEqual(size, sld_size_px)
356+
357+
# test size for QgsFontMarkerSymbolLayer
358+
sld = 'symbol_layer/QgsFontMarkerSymbolLayer.sld'
359+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
360+
layer.loadSldStyle(mFilePath)
361+
362+
sld_size_px = 6.23
363+
364+
sl = layer.renderer().symbol().symbolLayers()[0]
365+
size = sl.size()
366+
self.assertTrue(isinstance(sl, QgsFontMarkerSymbolLayer))
367+
self.assertEqual(unit, QgsUnitTypes.RenderPixels)
368+
self.assertEqual(size, sld_size_px)
369+
370+
def testSymbolSizeAfterReload(self):
371+
# create a layer
372+
layer = createLayerWithOnePoint()
373+
374+
# load a sld with marker size
375+
sld = 'symbol_layer/QgsSvgMarkerSymbolLayer.sld'
376+
mFilePath = os.path.join(TEST_DATA_DIR, sld)
377+
layer.loadSldStyle(mFilePath)
378+
379+
# get the size and unit of the symbol
380+
sl = layer.renderer().symbol().symbolLayers()[0]
381+
first_size = sl.size()
382+
first_unit = sl.outputUnit() # in pixels
383+
384+
# export sld into a qdomdocument with namespace processing activated
385+
doc = QDomDocument()
386+
msg = ""
387+
layer.exportSldStyle(doc, msg)
388+
doc.setContent(doc.toString(), True)
389+
self.assertTrue(msg == "")
390+
391+
# reload the same sld
392+
root = doc.firstChildElement("StyledLayerDescriptor")
393+
el = root.firstChildElement("NamedLayer")
394+
layer.readSld(el, msg)
395+
396+
# extract the size and unit of symbol
397+
sl = layer.renderer().symbol().symbolLayers()[0]
398+
second_size = sl.size()
399+
second_unit = sl.outputUnit()
400+
401+
# size and unit should be the same after export and reload the same
402+
# sld description
403+
self.assertEqual(first_size, second_size)
404+
self.assertEqual(first_unit, second_unit)
405+
114406

115407
if __name__ == '__main__':
116408
unittest.main()

tests/testdata/symbol_layer/QgsMarkerLineSymbolLayer.sld

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
<VendorOption name="placement">centralPoint</VendorOption>
1212
<se:Stroke>
1313
<se:GraphicStroke>
14+
<se:Gap>3.3</se:Gap>
15+
<se:PerpendicularOffset>6.6</se:PerpendicularOffset>
1416
<se:Graphic>
1517
<se:Mark>
1618
<se:WellKnownName>circle</se:WellKnownName>

tests/testdata/symbol_layer/QgsSimpleMarkerSymbolLayer.sld

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
<se:Name>Single symbol</se:Name>
1010
<se:PointSymbolizer>
1111
<se:Graphic>
12+
<se:Displacement>
13+
<se:DisplacementX>3.3</se:DisplacementX>
14+
<se:DisplacementY>6.6</se:DisplacementY>
15+
</se:Displacement>
1216
<se:Mark>
1317
<se:WellKnownName>pentagon</se:WellKnownName>
1418
<se:Fill>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" xmlns:se="http://www.opengis.net/se">
3+
<NamedLayer>
4+
<se:Name>022cs000</se:Name>
5+
<UserStyle>
6+
<se:Name>022cs000</se:Name>
7+
<se:FeatureTypeStyle>
8+
<se:Rule>
9+
<se:Name>Single symbol</se:Name>
10+
<se:PointSymbolizer uom="http://www.opengeospatial.org/se/units/foot">
11+
<se:Graphic>
12+
<se:ExternalGraphic>
13+
<OnlineResource xlink:type="simple" xlink:href="file:///gpsicons/skull.svg"/>
14+
<Format>image/svg+xml</Format>
15+
</se:ExternalGraphic>
16+
<se:Size>12</se:Size>
17+
<se:Rotation>
18+
<ogc:Literal>45</ogc:Literal>
19+
</se:Rotation>
20+
</se:Graphic>
21+
</se:PointSymbolizer>
22+
</se:Rule>
23+
</se:FeatureTypeStyle>
24+
</UserStyle>
25+
</NamedLayer>
26+
</StyledLayerDescriptor>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<StyledLayerDescriptor xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" xmlns:se="http://www.opengis.net/se">
3+
<NamedLayer>
4+
<se:Name>022cs000</se:Name>
5+
<UserStyle>
6+
<se:Name>022cs000</se:Name>
7+
<se:FeatureTypeStyle>
8+
<se:Rule>
9+
<se:Name>Single symbol</se:Name>
10+
<se:PointSymbolizer uom="http://www.opengeospatial.org/se/units/metre">
11+
<se:Graphic>
12+
<se:ExternalGraphic>
13+
<OnlineResource xlink:type="simple" xlink:href="file:///gpsicons/skull.svg"/>
14+
<Format>image/svg+xml</Format>
15+
</se:ExternalGraphic>
16+
<se:Size>12</se:Size>
17+
<se:Rotation>
18+
<ogc:Literal>45</ogc:Literal>
19+
</se:Rotation>
20+
</se:Graphic>
21+
</se:PointSymbolizer>
22+
</se:Rule>
23+
</se:FeatureTypeStyle>
24+
</UserStyle>
25+
</NamedLayer>
26+
</StyledLayerDescriptor>

0 commit comments

Comments
 (0)