From 26174ea9adda06da5492237698fabe55d2a70b51 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 15 May 2018 07:55:57 +1000 Subject: [PATCH] Copy cached min/max value to provider test suite --- tests/src/python/providertestbase.py | 134 ++++++++++++++++++++----- tests/testdata/provider/bug_17795.gpkg | Bin 118784 -> 118784 bytes 2 files changed, 109 insertions(+), 25 deletions(-) diff --git a/tests/src/python/providertestbase.py b/tests/src/python/providertestbase.py index c7cf0efb88a..deb3e31d602 100644 --- a/tests/src/python/providertestbase.py +++ b/tests/src/python/providertestbase.py @@ -9,6 +9,7 @@ the Free Software Foundation; either version 2 of the License, or from builtins import str from builtins import object + __author__ = 'Matthias Kuhn' __date__ = '2015-04-27' __copyright__ = 'Copyright 2015, The QGIS Project' @@ -35,7 +36,6 @@ from featuresourcetestbase import FeatureSourceTestCase class ProviderTestCase(FeatureSourceTestCase): - ''' This is a collection of tests for vector data providers and kept generic. To make use of it, subclass it and set self.source to a provider you want to test. @@ -101,15 +101,33 @@ class ProviderTestCase(FeatureSourceTestCase): self.assert_query(provider, 'ymax($geometry) > 80', [1, 2]) self.assert_query(provider, 'area($geometry) > 10', [1]) self.assert_query(provider, 'perimeter($geometry) < 12', [2, 3]) - self.assert_query(provider, 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'', [1, 3]) - self.assert_query(provider, 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')', [1, 3]) - self.assert_query(provider, 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))', [2]) - self.assert_query(provider, 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))', [2]) - self.assert_query(provider, 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', [1]) - self.assert_query(provider, 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', [1]) - self.assert_query(provider, 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', [1, 3]) - self.assert_query(provider, 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', [2]) - self.assert_query(provider, 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', [1, 2]) + self.assert_query(provider, + 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\')) = \'FF2FF1212\'', + [1, 3]) + self.assert_query(provider, + 'relate($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'), \'****F****\')', + [1, 3]) + self.assert_query(provider, + 'crosses($geometry,geom_from_wkt( \'Linestring (-68.2 82.1, -66.95 82.1, -66.95 79.05)\'))', + [2]) + self.assert_query(provider, + 'overlaps($geometry,geom_from_wkt( \'Polygon ((-68.2 82.1, -66.95 82.1, -66.95 79.05, -68.2 79.05, -68.2 82.1))\'))', + [2]) + self.assert_query(provider, + 'within($geometry,geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', + [1]) + self.assert_query(provider, + 'overlaps(translate($geometry,-1,-1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', + [1]) + self.assert_query(provider, + 'overlaps(buffer($geometry,1),geom_from_wkt( \'Polygon ((-75.1 76.1, -75.1 81.6, -68.8 81.6, -68.8 76.1, -75.1 76.1))\'))', + [1, 3]) + self.assert_query(provider, + 'intersects(centroid($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', + [2]) + self.assert_query(provider, + 'intersects(point_on_surface($geometry),geom_from_wkt( \'Polygon ((-74.4 78.2, -74.4 79.1, -66.8 79.1, -66.8 78.2, -74.4 78.2))\'))', + [1, 2]) self.assert_query(provider, 'distance($geometry,geom_from_wkt( \'Point (-70 70)\')) > 7', [1, 2]) def testGetFeaturesUncompiled(self): @@ -145,7 +163,8 @@ class ProviderTestCase(FeatureSourceTestCase): self.source.setSubsetString(None) expected = set([2, 3, 4]) - assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), result, subset) + assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), + result, subset) self.assertTrue(all_valid) # Subset string AND filter rect @@ -156,7 +175,8 @@ class ProviderTestCase(FeatureSourceTestCase): all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) self.source.setSubsetString(None) expected = set([2]) - assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), result, subset) + assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), + result, subset) self.assertTrue(all_valid) # Subset string AND filter rect, version 2 @@ -165,7 +185,8 @@ class ProviderTestCase(FeatureSourceTestCase): result = set([f['pk'] for f in self.source.getFeatures(QgsFeatureRequest().setFilterRect(extent))]) self.source.setSubsetString(None) expected = set([2, 4]) - assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), result, subset) + assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), + result, subset) # Subset string AND expression self.source.setSubsetString(subset) @@ -174,7 +195,8 @@ class ProviderTestCase(FeatureSourceTestCase): all_valid = (all(f.isValid() for f in self.source.getFeatures(request))) self.source.setSubsetString(None) expected = set([2, 4]) - assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), result, subset) + assert set(expected) == result, 'Expected {} and got {} when testing subset string {}'.format(set(expected), + result, subset) self.assertTrue(all_valid) def getSubsetString(self): @@ -330,8 +352,11 @@ class ProviderTestCase(FeatureSourceTestCase): self.assertTrue(provider_extent.isNull()) def testUnique(self): - self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('cnt'))), set([-200, 100, 200, 300, 400])) - assert set(['Apple', 'Honey', 'Orange', 'Pear', NULL]) == set(self.source.uniqueValues(self.source.fields().lookupField('name'))), 'Got {}'.format(set(self.source.uniqueValues(self.source.fields().lookupField('name')))) + self.assertEqual(set(self.source.uniqueValues(self.source.fields().lookupField('cnt'))), + set([-200, 100, 200, 300, 400])) + assert set(['Apple', 'Honey', 'Orange', 'Pear', NULL]) == set( + self.source.uniqueValues(self.source.fields().lookupField('name'))), 'Got {}'.format( + set(self.source.uniqueValues(self.source.fields().lookupField('name')))) if self.source.supportsSubsetString(): subset = self.getSubsetString2() @@ -352,7 +377,8 @@ class ProviderTestCase(FeatureSourceTestCase): self.assertEqual(len(result), 2) self.assertTrue(result.issubset(set(['Pear', 'Orange', 'Apple']))) - assert set([u'Apple', u'Honey', u'Orange', u'Pear', NULL]) == set(self.source.uniqueValues(field_index)), 'Got {}'.format(set(self.source.uniqueValues(field_index))) + assert set([u'Apple', u'Honey', u'Orange', u'Pear', NULL]) == set( + self.source.uniqueValues(field_index)), 'Got {}'.format(set(self.source.uniqueValues(field_index))) if self.source.supportsSubsetString(): subset = self.getSubsetString2() @@ -365,7 +391,7 @@ class ProviderTestCase(FeatureSourceTestCase): self.assertEqual(self.source.featureCount(), 5) if self.source.supportsSubsetString(): - #Add a subset string and test feature count + # Add a subset string and test feature count subset = self.getSubsetString() self.source.setSubsetString(subset) count = self.source.featureCount() @@ -425,7 +451,8 @@ class ProviderTestCase(FeatureSourceTestCase): else: # expect fail - self.assertFalse(l.dataProvider().addFeatures([f1, f2]), 'Provider reported no AddFeatures capability, but returned true to addFeatures') + self.assertFalse(l.dataProvider().addFeatures([f1, f2]), + 'Provider reported no AddFeatures capability, but returned true to addFeatures') def testAddFeatureFastInsert(self): if not getattr(self, 'getEditableLayer', None): @@ -465,7 +492,8 @@ class ProviderTestCase(FeatureSourceTestCase): f2.setAttributes([7, 330]) result, added = l.dataProvider().addFeatures([f1, f2]) - self.assertTrue(result, 'Provider returned False to addFeatures with missing attributes. Providers should accept these features but add NULL attributes to the end of the existing attributes to the required field length.') + self.assertTrue(result, + 'Provider returned False to addFeatures with missing attributes. Providers should accept these features but add NULL attributes to the end of the existing attributes to the required field length.') f1.setId(added[0].id()) f2.setId(added[1].id()) @@ -519,7 +547,8 @@ class ProviderTestCase(FeatureSourceTestCase): f2.setAttributes([8]) result, added = l.dataProvider().addFeatures([f1, f2]) - self.assertFalse(result, 'Provider returned True to addFeatures with incorrect geometry type. Providers should reject these features.') + self.assertFalse(result, + 'Provider returned True to addFeatures with incorrect geometry type. Providers should reject these features.') # make sure feature was not added added = [f for f in l.dataProvider().getFeatures() if f['pk'] == 7] @@ -561,7 +590,7 @@ class ProviderTestCase(FeatureSourceTestCase): l = self.getEditableLayer() self.assertTrue(l.isValid()) - #find 2 features to delete + # find 2 features to delete features = [f for f in l.dataProvider().getFeatures()] to_delete = [f.id() for f in features if f.attributes()[0] in [1, 3]] @@ -610,7 +639,8 @@ class ProviderTestCase(FeatureSourceTestCase): if l.dataProvider().capabilities() & QgsVectorDataProvider.FastTruncate or l.dataProvider().capabilities() & QgsVectorDataProvider.DeleteFeatures: # expect success result = l.dataProvider().truncate() - self.assertTrue(result, 'Provider reported FastTruncate or DeleteFeatures capability, but returned False to truncate()') + self.assertTrue(result, + 'Provider reported FastTruncate or DeleteFeatures capability, but returned False to truncate()') # check result features = [f['pk'] for f in l.dataProvider().getFeatures()] @@ -627,7 +657,7 @@ class ProviderTestCase(FeatureSourceTestCase): l = self.getEditableLayer() self.assertTrue(l.isValid()) - #find 2 features to change + # find 2 features to change features = [f for f in l.dataProvider().getFeatures()] # need to keep order here to_change = [f for f in features if f.attributes()[0] == 1] @@ -640,7 +670,8 @@ class ProviderTestCase(FeatureSourceTestCase): if l.dataProvider().capabilities() & QgsVectorDataProvider.ChangeAttributeValues: # expect success result = l.dataProvider().changeAttributeValues(changes) - self.assertTrue(result, 'Provider reported ChangeAttributeValues capability, but returned False to changeAttributeValues') + self.assertTrue(result, + 'Provider reported ChangeAttributeValues capability, but returned False to changeAttributeValues') # check result self.testGetFeatures(l.dataProvider(), changed_attributes=new_attr_map) @@ -733,3 +764,56 @@ class ProviderTestCase(FeatureSourceTestCase): # expect fail self.assertFalse(l.dataProvider().changeFeatures(attribute_changes, geometry_changes), 'Provider reported no ChangeAttributeValues capability, but returned true to changeFeatures') + + def testMinMaxAfterChanges(self): + """ + Tests retrieving field min and max value after making changes to the provider's features + """ + if not getattr(self, 'getEditableLayer', None): + return + + vl = self.getEditableLayer() + self.assertTrue(vl.isValid()) + + self.assertEqual(vl.dataProvider().minimumValue(0), 1) + self.assertEqual(vl.dataProvider().minimumValue(1), -200) + self.assertEqual(vl.dataProvider().maximumValue(0), 5) + self.assertEqual(vl.dataProvider().maximumValue(1), 400) + + # add feature + f6 = QgsFeature() + f6.setAttributes([15, 1400]) + res, [f6] = vl.dataProvider().addFeatures([f6]) + self.assertTrue(res) + self.assertEqual(vl.dataProvider().minimumValue(0), 1) + self.assertEqual(vl.dataProvider().minimumValue(1), -200) + self.assertEqual(vl.dataProvider().maximumValue(0), 15) + self.assertEqual(vl.dataProvider().maximumValue(1), 1400) + f7 = QgsFeature() + f7.setAttributes([0, -1400]) + res, [f7] = vl.dataProvider().addFeatures([f7]) + self.assertTrue(res) + self.assertEqual(vl.dataProvider().minimumValue(0), 0) + self.assertEqual(vl.dataProvider().minimumValue(1), -1400) + self.assertEqual(vl.dataProvider().maximumValue(0), 15) + self.assertEqual(vl.dataProvider().maximumValue(1), 1400) + + # change attribute values + self.assertTrue(vl.dataProvider().changeAttributeValues({f6.id(): {1: 150}, f7.id(): {1: -100}})) + self.assertEqual(vl.dataProvider().minimumValue(1), -200) + self.assertEqual(vl.dataProvider().maximumValue(1), 400) + + # delete features + f1 = [f for f in vl.getFeatures() if f['pk'] == 5][0] + f3 = [f for f in vl.getFeatures() if f['pk'] == 3][0] + self.assertTrue(vl.dataProvider().deleteFeatures([f6.id(), f7.id()])) + self.assertEqual(vl.dataProvider().minimumValue(0), 1) + self.assertEqual(vl.dataProvider().minimumValue(1), -200) + self.assertEqual(vl.dataProvider().maximumValue(0), 5) + self.assertEqual(vl.dataProvider().maximumValue(1), 400) + + if vl.dataProvider().capabilities() & QgsVectorDataProvider.DeleteAttributes: + # delete attributes + self.assertTrue(vl.dataProvider().deleteAttributes([0])) + self.assertEqual(vl.dataProvider().minimumValue(0), -200) + self.assertEqual(vl.dataProvider().maximumValue(0), 400) diff --git a/tests/testdata/provider/bug_17795.gpkg b/tests/testdata/provider/bug_17795.gpkg index 7e5fca505083bd49bb39fd452d84dbcea5edb6e1..e92c2b13bb2d6394b285f01a80d82dcdb1fd345f 100644 GIT binary patch delta 26 icmZozz}~QceS$Qj_e2?IR&NG9nGKC8TT>Y4oCg4K@CfPv delta 26 icmZozz}~QceS$Qj_Cy(HR&55|k2@Muwx%%7IS&AJ0||xz