Skip to content

Commit

Permalink
Merge pull request #51453 from pblottiere/wfs_nil
Browse files Browse the repository at this point in the history
Do not add property with NULL value in GetFeature doc
  • Loading branch information
pblottiere committed Jan 16, 2023
2 parents da47e54 + 38015ef commit 508d96e
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 22 deletions.
46 changes: 26 additions & 20 deletions src/server/services/wfs/CMakeLists.txt
Expand Up @@ -21,33 +21,39 @@ set (WFS_HDRS
########################################################
# Build

add_library (wfs MODULE ${WFS_SRCS} ${WFS_HDRS})
set(_library_suffix_MODULE "")
set(_library_suffix_STATIC "_static")

# require c++17
target_compile_features(wfs PRIVATE cxx_std_17)
foreach(_library_type MODULE STATIC)
set(_library_name "wfs${_library_suffix_${_library_type}}")

include_directories(SYSTEM
${GDAL_INCLUDE_DIR}
${POSTGRES_INCLUDE_DIR}
)
add_library (${_library_name} ${_library_type} ${WFS_SRCS} ${WFS_HDRS})

include_directories(
${CMAKE_SOURCE_DIR}/src/server
${CMAKE_SOURCE_DIR}/src/server/services
${CMAKE_SOURCE_DIR}/src/server/services/wfs
# require c++17
target_compile_features(${_library_name} PRIVATE cxx_std_17)

${CMAKE_BINARY_DIR}/src/python
${CMAKE_BINARY_DIR}/src/analysis
${CMAKE_BINARY_DIR}/src/server
include_directories(${_library_name} SYSTEM PUBLIC
${GDAL_INCLUDE_DIR}
${POSTGRES_INCLUDE_DIR}
)

${CMAKE_CURRENT_BINARY_DIR}
)
target_include_directories(${_library_name} PUBLIC
${CMAKE_SOURCE_DIR}/src/server
${CMAKE_SOURCE_DIR}/src/server/services
${CMAKE_SOURCE_DIR}/src/server/services/wfs

${CMAKE_BINARY_DIR}/src/python
${CMAKE_BINARY_DIR}/src/analysis
${CMAKE_BINARY_DIR}/src/server

target_link_libraries(wfs
qgis_core
qgis_server
)
${CMAKE_CURRENT_BINARY_DIR}
)

target_link_libraries(${_library_name}
qgis_core
qgis_server
)
endforeach()


########################################################
Expand Down
4 changes: 2 additions & 2 deletions src/server/services/wfs/qgswfsgetfeature.cpp
Expand Up @@ -1448,7 +1448,7 @@ namespace QgsWfs
for ( int i = 0; i < params.attributeIndexes.count(); ++i )
{
int idx = params.attributeIndexes[i];
if ( idx >= fields.count() )
if ( idx >= fields.count() || QgsVariantUtils::isNull( featureAttributes[idx] ) )
{
continue;
}
Expand Down Expand Up @@ -1545,7 +1545,7 @@ namespace QgsWfs
for ( int i = 0; i < params.attributeIndexes.count(); ++i )
{
int idx = params.attributeIndexes[i];
if ( idx >= fields.count() )
if ( idx >= fields.count() || QgsVariantUtils::isNull( featureAttributes[idx] ) )
{
continue;
}
Expand Down
1 change: 1 addition & 0 deletions tests/src/server/CMakeLists.txt
@@ -1,5 +1,6 @@
if(NOT MSVC)
add_subdirectory(wms)
add_subdirectory(wfs)
endif()

include_directories(${CMAKE_CURRENT_SOURCE_DIR}
Expand Down
45 changes: 45 additions & 0 deletions tests/src/server/wfs/CMakeLists.txt
@@ -0,0 +1,45 @@
#####################################################
# Don't forget to include output directory, otherwise
# the UI file won't be wrapped!
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src/test
${CMAKE_SOURCE_DIR}/src/server
${CMAKE_SOURCE_DIR}/src/server/services
${CMAKE_SOURCE_DIR}/src/server/services/wfs

${CMAKE_BINARY_DIR}/src/server

${CMAKE_CURRENT_BINARY_DIR}
)

#note for tests we should not include the moc of our
#qtests in the executable file list as the moc is
#directly included in the sources
#and should not be compiled twice. Trying to include
#them in will cause an error at build time

#No relinking and full RPATH for the install tree
#See: http://www.cmake.org/Wiki/CMake_RPATH_handling#No_relinking_and_full_RPATH_for_the_install_tree
set(MODULE_WFS_SRCS
${CMAKE_SOURCE_DIR}/src/server/services/wfs/qgswfsgetfeature.cpp
)

set(MODULE_WFS_HDRS
)

if (BUILD_WITH_QT6)
QT6_WRAP_CPP(MODULE_WFS_MOC_SRCS ${MODULE_WFS_HDRS})
else()
QT5_WRAP_CPP(MODULE_WFS_MOC_SRCS ${MODULE_WFS_HDRS})
endif()

#############################################################
# Tests:

set(TESTS
test_qgsserver_wfs_getfeature.cpp
)

foreach(TESTSRC ${TESTS})
ADD_QGIS_TEST(${TESTSRC} MODULE server LINKEDLIBRARIES qgis_server wfs_static)
endforeach(TESTSRC)
151 changes: 151 additions & 0 deletions tests/src/server/wfs/test_qgsserver_wfs_getfeature.cpp
@@ -0,0 +1,151 @@
/***************************************************************************
test_qgsserver_wfs_getfeature.cpp
---------------------------------
Date : 12 Jan 2023
Copyright : (C) 2022 by Paul Blottiere
Email : paul dot blottiere @ gmail.com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgstest.h"
#include "qgsproject.h"
#include "qgsvectorlayer.h"
#include "qgsfeaturerequest.h"

#include "qgsbufferserverresponse.h"
#include "qgsserverinterfaceimpl.h"
#include "qgswfsgetfeature.h"

/**
* \ingroup UnitTests
* This is a unit test for the WMS parameters class
*/
class TestQgsServerWfsGetFeature : public QObject
{
Q_OBJECT

private slots:
void initTestCase();
void cleanupTestCase();

void nullValueProperty();
};

void TestQgsServerWfsGetFeature::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();
}

void TestQgsServerWfsGetFeature::cleanupTestCase()
{
QgsApplication::exitQgis();
}

void TestQgsServerWfsGetFeature::nullValueProperty()
{
// init server iface
QgsCapabilitiesCache cache;
QgsServiceRegistry registry;
QgsServerSettings settings;
QgsServerInterfaceImpl interface( &cache, &registry, &settings );

// init project
QgsProject project;

QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=name0:int&field=name1:int&field=name2:int" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );

QgsFields fields;
const QgsField field0( QStringLiteral( "name0" ) );
fields.append( field0 );
const QgsField field1( QStringLiteral( "name1" ) );
fields.append( field1 );
const QgsField field2( QStringLiteral( "name2" ) );
fields.append( field2 );

QgsFeature f;
f.setFields( fields, true );
f.setAttribute( 0, QVariant( 0 ) );
f.setAttribute( 1, QVariant() );
f.setAttribute( 2, QVariant() );
f.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( 0.50, 0.50 ) ) );
std::cout << "feature is valid: " << f.isValid() << std::endl;

vl->startEditing();
vl->addFeature( f );
vl->commitChanges();
std::cout << "feature count: " << vl->featureCount() << std::endl;

project.addMapLayer( vl );

QStringList wfsLayers;
wfsLayers << vl->id();
project.writeEntry( "WFSLayers", "/", wfsLayers );

//
// GML2
//

// build response
QgsServerRequest gml2Request;
gml2Request.setParameter( "VERSION", "1.0.0" );
gml2Request.setParameter( "TYPENAME", "vl" );
gml2Request.setParameter( "OUTPUTFORMAT", "gml2" );

QgsBufferServerResponse gml2Response;
QgsWfs::writeGetFeature( &interface, &project, "", gml2Request, gml2Response );

// check response
QDomDocument gml2Xml;
gml2Xml.setContent( gml2Response.body() );

const QDomElement gml2Elem = gml2Xml.documentElement();
const QDomNode gml2FeatureNode = gml2Elem.elementsByTagName( "gml:featureMember" ).at( 0 ).firstChild();
const QDomNodeList gml2Children = gml2FeatureNode.childNodes();

// attributes for fields name1 and name2 are NULL (QVariant()) for the
// feature f, so it's not added in the resulting document. This way, the XML
// only contains 3 children:
// - <gml:boundedBy>
// - <qgs:geometry>
// - <qgs:name0>0</qgs:name0>
QCOMPARE( gml2Children.count(), 3 );

//
// GML3
//

// build response
QgsServerRequest gml3Request;
gml3Request.setParameter( "VERSION", "1.0.0" );
gml3Request.setParameter( "TYPENAME", "vl" );
gml3Request.setParameter( "OUTPUTFORMAT", "gml3" );

QgsBufferServerResponse gml3Response;
QgsWfs::writeGetFeature( &interface, &project, "", gml3Request, gml3Response );

// check response
QDomDocument gml3Xml;
gml3Xml.setContent( gml3Response.body() );

const QDomElement gml3Elem = gml3Xml.documentElement();
const QDomNode gml3FeatureNode = gml3Elem.elementsByTagName( "gml:featureMember" ).at( 0 ).firstChild();
const QDomNodeList gml3Children = gml3FeatureNode.childNodes();

// attributes for fields name1 and name2 are NULL (QVariant()) for the
// feature f, so it's not added in the resulting document. This way, the XML
// only contains 3 children:
// - <gml:boundedBy>
// - <qgs:geometry>
// - <qgs:name0>0</qgs:name0>
QCOMPARE( gml3Children.count(), 3 );
}

QGSTEST_MAIN( TestQgsServerWfsGetFeature )
#include "test_qgsserver_wfs_getfeature.moc"

0 comments on commit 508d96e

Please sign in to comment.