@@ -3581,6 +3581,162 @@ def testGeometryCollectionAsMultiLineString(self):
3581
3581
vl_extent = QgsGeometry .fromRect (vl .extent ())
3582
3582
assert QgsGeometry .compare (vl_extent .asPolygon ()[0 ], reference .asPolygon ()[0 ], 0.00001 ), 'Expected {}, got {}' .format (reference .asWkt (), vl_extent .asWkt ())
3583
3583
3584
+ def test_NullValues_regression_20961 (self ):
3585
+ """Test that provider handles null values, regression #20961"""
3586
+
3587
+ endpoint = self .__class__ .basetestpath + '/fake_qgis_http_endpoint_null_values'
3588
+
3589
+ with open (sanitize (endpoint , '?SERVICE=WFS?REQUEST=GetCapabilities?VERSION=1.1.0' ), 'wb' ) as f :
3590
+ f .write ("""
3591
+ <wfs:WFS_Capabilities version="1.1.0" xmlns="http://www.opengis.net/wfs" xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:ows="http://www.opengis.net/ows" xmlns:gml="http://schemas.opengis.net/gml">
3592
+ <FeatureTypeList>
3593
+ <FeatureType>
3594
+ <Name>points</Name>
3595
+ <Title>Title</Title>
3596
+ <Abstract>Abstract</Abstract>
3597
+ <DefaultCRS>urn:ogc:def:crs:OGC:1.3:CRS84</DefaultCRS>
3598
+ <WGS84BoundingBox>
3599
+ <LowerCorner>-98.6523 32.7233</LowerCorner>
3600
+ <UpperCorner>23.2868 69.9882</UpperCorner>
3601
+ </WGS84BoundingBox>
3602
+ </FeatureType>
3603
+ </FeatureTypeList>
3604
+ </wfs:WFS_Capabilities>""" .encode ('UTF-8' ))
3605
+
3606
+ with open (sanitize (endpoint , '?SERVICE=WFS&REQUEST=DescribeFeatureType&VERSION=1.1.0&TYPENAME=points' ), 'wb' ) as f :
3607
+ f .write ("""
3608
+ <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" version="1.0" xmlns:ogc="http://www.opengis.net/ogc" xmlns:qgs="http://www.qgis.org/gml" elementFormDefault="qualified" targetNamespace="http://www.qgis.org/gml" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
3609
+ <import schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/gml.xsd" namespace="http://www.opengis.net/gml"/>
3610
+ <element type="qgs:pointsType" name="points" substitutionGroup="gml:_Feature"/>
3611
+ <complexType name="pointsType">
3612
+ <complexContent>
3613
+ <extension base="gml:AbstractFeatureType">
3614
+ <sequence>
3615
+ <element type="gml:MultiPointPropertyType" name="geometry" minOccurs="0" maxOccurs="1"/>
3616
+ <element type="int" name="id"/>
3617
+ <element type="string" name="name"/>
3618
+ <element type="int" name="type" nillable="true"/>
3619
+ <element type="decimal" name="elevation" nillable="true"/>
3620
+ </sequence>
3621
+ </extension>
3622
+ </complexContent>
3623
+ </complexType>
3624
+ </schema>
3625
+ """ .encode ('UTF-8' ))
3626
+
3627
+ get_feature_1 = """<wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" xmlns:ows="http://www.opengis.net/ows" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:qgs="http://www.qgis.org/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd http://www.qgis.org/gml http://localhost:8000/ows/bug_20961_server?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0&SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=points&OUTPUTFORMAT=text/xml; subtype%3Dgml/3.1.1">
3628
+ <gml:boundedBy>
3629
+ <gml:Envelope srsName="EPSG:3857">
3630
+ <gml:lowerCorner>-10981925.67093 3858635.0686243</gml:lowerCorner>
3631
+ <gml:upperCorner>2592274.0488407 11064877.6393476</gml:upperCorner>
3632
+ </gml:Envelope>
3633
+ </gml:boundedBy>
3634
+ <gml:featureMember>
3635
+ <qgs:points gml:id="points.177">
3636
+ <gml:boundedBy>
3637
+ <gml:Envelope srsName="EPSG:3857">
3638
+ <gml:lowerCorner>1544231.80343599 5930698.04174612</gml:lowerCorner>
3639
+ <gml:upperCorner>1544231.80343599 5930698.04174612</gml:upperCorner>
3640
+ </gml:Envelope>
3641
+ </gml:boundedBy>
3642
+ <qgs:geometry>
3643
+ <MultiPoint xmlns="http://www.opengis.net/gml" srsName="EPSG:3857">
3644
+ <pointMember xmlns="http://www.opengis.net/gml">
3645
+ <Point xmlns="http://www.opengis.net/gml">
3646
+ <pos xmlns="http://www.opengis.net/gml" srsDimension="2">1544231.80343599 5930698.04174612</pos>
3647
+ </Point>
3648
+ </pointMember>
3649
+ </MultiPoint>
3650
+ </qgs:geometry>
3651
+ <qgs:id>177</qgs:id>
3652
+ <qgs:name>Xxx</qgs:name>
3653
+ <qgs:elevation_source></qgs:elevation_source>
3654
+ </qgs:points>
3655
+ </gml:featureMember>
3656
+ </wfs:FeatureCollection>
3657
+ """
3658
+ get_features = """<wfs:FeatureCollection xmlns:wfs="http://www.opengis.net/wfs" xmlns:ogc="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml" xmlns:ows="http://www.opengis.net/ows" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:qgs="http://www.qgis.org/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd http://www.qgis.org/gml http://localhost:8000/ows/bug_20961_server?ACCEPTVERSIONS=2.0.0,1.1.0,1.0.0&SERVICE=WFS&VERSION=1.1.0&REQUEST=DescribeFeatureType&TYPENAME=points&OUTPUTFORMAT=text/xml; subtype%3Dgml/3.1.1">
3659
+ <gml:boundedBy>
3660
+ <gml:Envelope srsName="EPSG:3857">
3661
+ <gml:lowerCorner>-10981925.67093 3858635.0686243</gml:lowerCorner>
3662
+ <gml:upperCorner>2592274.0488407 11064877.6393476</gml:upperCorner>
3663
+ </gml:Envelope>
3664
+ </gml:boundedBy>
3665
+ <gml:featureMember>
3666
+ <qgs:points gml:id="points.177">
3667
+ <gml:boundedBy>
3668
+ <gml:Envelope srsName="EPSG:3857">
3669
+ <gml:lowerCorner>1544231.80343599 5930698.04174612</gml:lowerCorner>
3670
+ <gml:upperCorner>1544231.80343599 5930698.04174612</gml:upperCorner>
3671
+ </gml:Envelope>
3672
+ </gml:boundedBy>
3673
+ <qgs:geometry>
3674
+ <MultiPoint xmlns="http://www.opengis.net/gml" srsName="EPSG:3857">
3675
+ <pointMember xmlns="http://www.opengis.net/gml">
3676
+ <Point xmlns="http://www.opengis.net/gml">
3677
+ <pos xmlns="http://www.opengis.net/gml" srsDimension="2">1544231.80343599 5930698.04174612</pos>
3678
+ </Point>
3679
+ </pointMember>
3680
+ </MultiPoint>
3681
+ </qgs:geometry>
3682
+ <qgs:id>177</qgs:id>
3683
+ <qgs:name>Xxx</qgs:name>
3684
+ <qgs:type xsi:nil="true"></qgs:type>
3685
+ <qgs:elevation xsi:nil="true"></qgs:elevation>
3686
+ </qgs:points>
3687
+ </gml:featureMember>
3688
+ <gml:featureMember>
3689
+ <qgs:points gml:id="points.5">
3690
+ <gml:boundedBy>
3691
+ <gml:Envelope srsName="EPSG:3857">
3692
+ <gml:lowerCorner>-10977033.701121 3897159.3308746</gml:lowerCorner>
3693
+ <gml:upperCorner>-10977033.701121 3897159.3308746</gml:upperCorner>
3694
+ </gml:Envelope>
3695
+ </gml:boundedBy>
3696
+ <qgs:geometry>
3697
+ <MultiPoint xmlns="http://www.opengis.net/gml" srsName="EPSG:3857">
3698
+ <pointMember xmlns="http://www.opengis.net/gml">
3699
+ <Point xmlns="http://www.opengis.net/gml">
3700
+ <pos xmlns="http://www.opengis.net/gml" srsDimension="2">-10977033.701121 3897159.3308746</pos>
3701
+ </Point>
3702
+ </pointMember>
3703
+ </MultiPoint>
3704
+ </qgs:geometry>
3705
+ <qgs:id>5</qgs:id>
3706
+ <qgs:name>sdf</qgs:name>
3707
+ <qgs:type>0</qgs:type>
3708
+ <qgs:elevation xsi:nil="true"></qgs:elevation>
3709
+ </qgs:points>
3710
+ </gml:featureMember>
3711
+ </wfs:FeatureCollection>"""
3712
+
3713
+ with open (sanitize (endpoint , """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&MAXFEATURES=1&SRSNAME=urn:ogc:def:crs:EPSG::4326""" ), 'wb' ) as f :
3714
+ f .write (get_feature_1 .encode ('UTF-8' ))
3715
+
3716
+ with open (sanitize (endpoint , """?SERVICE=WFS&REQUEST=GetFeature&VERSION=1.1.0&TYPENAME=points&SRSNAME=urn:ogc:def:crs:EPSG::4326""" ), 'wb' ) as f :
3717
+ f .write (get_features .encode ('UTF-8' ))
3718
+
3719
+ vl = QgsVectorLayer ("url='http://" + endpoint + "' typename='points' version='1.1.0'" , 'test' , 'WFS' )
3720
+ self .assertTrue (vl .isValid ())
3721
+
3722
+ got_f = [f for f in vl .getFeatures ()]
3723
+ self .assertEqual (str (got_f [0 ]['type' ]), 'NULL' )
3724
+ self .assertEqual (str (got_f [0 ]['elevation' ]), 'NULL' )
3725
+ self .assertEqual (str (got_f [0 ]['name' ]), 'Xxx' )
3726
+ self .assertEqual (str (got_f [1 ]['type' ]), '0' )
3727
+ self .assertEqual (str (got_f [1 ]['elevation' ]), 'NULL' )
3728
+ self .assertEqual (str (got_f [1 ]['name' ]), 'sdf' )
3729
+
3730
+ # Now iterate ! Regression #20961
3731
+ ids = [f .id () for f in got_f ]
3732
+ got_f2 = [vl .getFeature (id ) for id in ids ]
3733
+ self .assertEqual (str (got_f2 [0 ]['type' ]), 'NULL' )
3734
+ self .assertEqual (str (got_f2 [0 ]['elevation' ]), 'NULL' )
3735
+ self .assertEqual (str (got_f2 [0 ]['name' ]), 'Xxx' )
3736
+ self .assertEqual (str (got_f2 [1 ]['type' ]), '0' )
3737
+ self .assertEqual (str (got_f2 [1 ]['elevation' ]), 'NULL' )
3738
+ self .assertEqual (str (got_f2 [1 ]['name' ]), 'sdf' )
3739
+
3584
3740
3585
3741
if __name__ == '__main__' :
3586
3742
unittest .main ()
0 commit comments