Merge pull request #30378 from rldhont/tests_pyqgsogcutils

[Tests] Add PyQgsOgcUtils
This commit is contained in:
rldhont 2019-07-02 09:17:32 +02:00 committed by GitHub
commit 4a5c5f2fff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 375 additions and 6 deletions

View File

@ -378,6 +378,34 @@ bool QgsField::convertCompatible( QVariant &v ) const
return true;
}
//String representations of doubles in QVariant will return false to convert( QVariant::LongLong )
//work around this by first converting to double, and then checking whether the double is convertible to longlong
if ( d->type == QVariant::LongLong && v.canConvert( QVariant::Double ) )
{
//firstly test the conversion to longlong because conversion to double will rounded the value
QVariant tmp( v );
if ( !tmp.convert( d->type ) )
{
bool ok = false;
double dbl = v.toDouble( &ok );
if ( !ok )
{
//couldn't convert to number
v = QVariant( d->type );
return false;
}
double round = std::round( dbl );
if ( round > std::numeric_limits<long long>::max() || round < -std::numeric_limits<long long>::max() )
{
//double too large to fit in longlong
v = QVariant( d->type );
return false;
}
v = QVariant( static_cast< long long >( std::round( dbl ) ) );
return true;
}
}
if ( !v.convert( d->type ) )
{

View File

@ -524,12 +524,6 @@ void TestQgsField::convertCompatible()
QVERIFY( intField.convertCompatible( smallLonglong ) );
QCOMPARE( smallLonglong.type(), QVariant::Int );
QCOMPARE( smallLonglong, QVariant( 99 ) );
//conversion of longlong to longlong field
QgsField longlongField( QStringLiteral( "long" ), QVariant::LongLong, QStringLiteral( "longlong" ) );
longlong = QVariant( 99999999999999999LL );
QVERIFY( longlongField.convertCompatible( longlong ) );
QCOMPARE( longlong.type(), QVariant::LongLong );
QCOMPARE( longlong, QVariant( 99999999999999999LL ) );
//string representation of an int
QVariant stringInt( "123456" );
@ -542,6 +536,13 @@ void TestQgsField::convertCompatible()
QCOMPARE( stringInt.type(), QVariant::Int );
QCOMPARE( stringInt, QVariant( "123456" ) );
//conversion of longlong to longlong field
QgsField longlongField( QStringLiteral( "long" ), QVariant::LongLong, QStringLiteral( "longlong" ) );
longlong = QVariant( 99999999999999999LL );
QVERIFY( longlongField.convertCompatible( longlong ) );
QCOMPARE( longlong.type(), QVariant::LongLong );
QCOMPARE( longlong, QVariant( 99999999999999999LL ) );
//string representation of a longlong
QVariant stringLong( "99999999999999999" );
QVERIFY( longlongField.convertCompatible( stringLong ) );
@ -553,6 +554,30 @@ void TestQgsField::convertCompatible()
QCOMPARE( stringLong.type(), QVariant::LongLong );
QCOMPARE( stringLong, QVariant( 99999999999999999LL ) );
//conversion of string double value to longlong
notNumberString = QVariant( "notanumber" );
QVERIFY( !longlongField.convertCompatible( notNumberString ) );
QCOMPARE( notNumberString.type(), QVariant::LongLong );
QVERIFY( notNumberString.isNull() );
//small double, should be rounded
smallDoubleString = QVariant( "45.7" );
QVERIFY( longlongField.convertCompatible( smallDoubleString ) );
QCOMPARE( smallDoubleString.type(), QVariant::LongLong );
QCOMPARE( smallDoubleString, QVariant( 46 ) );
negativeSmallDoubleString = QVariant( "-9345.754534525235235" );
QVERIFY( longlongField.convertCompatible( negativeSmallDoubleString ) );
QCOMPARE( negativeSmallDoubleString.type(), QVariant::LongLong );
QCOMPARE( negativeSmallDoubleString, QVariant( -9346 ) );
//large double, can be converted
largeDoubleString = QVariant( "9999999999.99" );
QVERIFY( longlongField.convertCompatible( largeDoubleString ) );
QCOMPARE( largeDoubleString.type(), QVariant::LongLong );
QCOMPARE( largeDoubleString, QVariant( 10000000000LL ) );
//extra large double, cannot be converted
largeDoubleString = QVariant( "999999999999999999999.99" );
QVERIFY( !longlongField.convertCompatible( largeDoubleString ) );
QCOMPARE( largeDoubleString.type(), QVariant::LongLong );
QVERIFY( largeDoubleString.isNull() );
//string representation of a double
QVariant stringDouble( "123456.012345" );

View File

@ -147,6 +147,7 @@ ADD_PYTHON_TEST(PyQgsNetworkContentFetcherTask test_qgsnetworkcontentfetchertask
ADD_PYTHON_TEST(PyQgsNullSymbolRenderer test_qgsnullsymbolrenderer.py)
ADD_PYTHON_TEST(PyQgsNewGeoPackageLayerDialog test_qgsnewgeopackagelayerdialog.py)
ADD_PYTHON_TEST(PyQgsNoApplication test_qgsnoapplication.py)
ADD_PYTHON_TEST(PyQgsOgcUtils test_qgsogcutils.py)
ADD_PYTHON_TEST(PyQgsOGRProviderGpkg test_provider_ogr_gpkg.py)
ADD_PYTHON_TEST(PyQgsOGRProviderSqlite test_provider_ogr_sqlite.py)
ADD_PYTHON_TEST(PyQgsOpacityWidget test_qgsopacitywidget.py)

View File

@ -0,0 +1,315 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsOgcUtils.
From build dir, run: ctest -R PyQgsOgcUtils -V
.. note:: 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.
"""
__author__ = 'René-Luc Dhont'
__date__ = '21/06/2019'
__copyright__ = 'Copyright 2019, The QGIS Project'
import qgis # NOQA switch sip api
from qgis.PyQt.QtCore import QVariant
from qgis.PyQt.QtXml import QDomDocument
from qgis.core import QgsOgcUtils, QgsVectorLayer, QgsField
from qgis.testing import start_app, unittest
start_app()
class TestQgsOgcUtils(unittest.TestCase):
def test_expressionFromOgcFilterWithInt(self):
"""
Test expressionFromOgcFilter with Int type field
"""
vl = QgsVectorLayer('Point', 'vl', 'memory')
vl.dataProvider().addAttributes([QgsField('id', QVariant.Int)])
vl.updateFields()
# Literals are Integer 1 and 3
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > 1 AND id < 3')
# Literals are Double 1.0 and 3.0
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1.0</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3.0</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > 1 AND id < 3')
# Literals are Double 1.5 and 3.5
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1.5</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3.5</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > 2 AND id < 4')
def test_expressionFromOgcFilterWithLonglong(self):
"""
Test expressionFromOgcFilter with LongLong type field
"""
vl = QgsVectorLayer('Point', 'vl', 'memory')
vl.dataProvider().addAttributes([QgsField('id', QVariant.LongLong)])
vl.updateFields()
# Literals are Integer 1 and 3
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > 1 AND id < 3')
# Literals are Double 1.0 and 3.0
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1.0</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3.0</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > 1 AND id < 3')
# Literals are Double 1.5 and 3.5
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1.5</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3.5</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > 2 AND id < 4')
def test_expressionFromOgcFilterWithDouble(self):
"""
Test expressionFromOgcFilter with Double type field
"""
vl = QgsVectorLayer('Point', 'vl', 'memory')
vl.dataProvider().addAttributes([QgsField('id', QVariant.Double)])
vl.updateFields()
# Literals are Integer 1 and 3
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > 1 AND id < 3')
# Literals are Double 1.0 and 3.0
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1.0</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3.0</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > 1 AND id < 3')
# Literals are Double 1.5 and 3.5
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1.5</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3.5</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > 1.5 AND id < 3.5')
def test_expressionFromOgcFilterWithString(self):
"""
Test expressionFromOgcFilter with String type field
"""
vl = QgsVectorLayer('Point', 'vl', 'memory')
vl.dataProvider().addAttributes([QgsField('id', QVariant.String)])
vl.updateFields()
# Literals are Integer 1 and 3
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > \'1\' AND id < \'3\'')
# Literals are Double 1.0 and 3.0
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1.0</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3.0</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > \'1.0\' AND id < \'3.0\'')
# Literals are Double 1.5 and 3.5
f = '''<?xml version="1.0" encoding="UTF-8"?>
<ogc:Filter xmlns:ogc="http://www.opengis.net/ogc">
<ogc:And>
<ogc:PropertyIsGreaterThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>1.5</ogc:Literal>
</ogc:PropertyIsGreaterThan>
<ogc:PropertyIsLessThan>
<ogc:PropertyName>id</ogc:PropertyName>
<ogc:Literal>3.5</ogc:Literal>
</ogc:PropertyIsLessThan>
</ogc:And>
</ogc:Filter>
'''
d = QDomDocument('filter')
d.setContent(f, True)
e = QgsOgcUtils.expressionFromOgcFilter(d.documentElement(), vl)
self.assertEqual(e.expression(), 'id > \'1.5\' AND id < \'3.5\'')
if __name__ == '__main__':
unittest.main()