"""QGIS Unit tests for Processing CheckValidity algorithm. .. 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__ = "Alessandro Pasotti" __date__ = "2018-09" __copyright__ = "Copyright 2018, The QGIS Project" from qgis.PyQt.QtCore import QCoreApplication, QVariant from qgis.core import ( QgsFeature, QgsGeometry, QgsApplication, QgsMemoryProviderUtils, QgsWkbTypes, QgsField, QgsFields, QgsProcessingContext, QgsProcessingFeedback, QgsCoordinateReferenceSystem, QgsProject, QgsProcessingException, QgsProcessingUtils, QgsSettings, ) from processing.core.Processing import Processing from processing.gui.AlgorithmExecutor import execute import unittest from qgis.testing import start_app, QgisTestCase from qgis.PyQt.QtTest import QSignalSpy from qgis.analysis import QgsNativeAlgorithms start_app() class ConsoleFeedBack(QgsProcessingFeedback): def reportError(self, error, fatalError=False): print(error) class TestQgsProcessingCheckValidity(QgisTestCase): @classmethod def setUpClass(cls): """Run before all tests""" super().setUpClass() QCoreApplication.setOrganizationName("QGIS_Test") QCoreApplication.setOrganizationDomain( "QGIS_TestPyQgsProcessingCheckValidity.com" ) QCoreApplication.setApplicationName("QGIS_TestPyQgsProcessingCheckValidity") QgsSettings().clear() Processing.initialize() cls.registry = QgsApplication.instance().processingRegistry() def _make_layer(self, layer_wkb_name): fields = QgsFields() wkb_type = getattr(QgsWkbTypes, layer_wkb_name) fields.append(QgsField("int_f", QVariant.Int)) layer = QgsMemoryProviderUtils.createMemoryLayer( "%s_layer" % layer_wkb_name, fields, wkb_type, QgsCoordinateReferenceSystem("EPSG:4326"), ) self.assertTrue(layer.isValid()) self.assertEqual(layer.wkbType(), wkb_type) return layer def test_check_validity(self): """Test that the output invalid contains the error reason""" polygon_layer = self._make_layer("Polygon") self.assertTrue(polygon_layer.startEditing()) f = QgsFeature(polygon_layer.fields()) f.setAttributes([1]) # Flake! f.setGeometry(QgsGeometry.fromWkt("POLYGON ((0 0, 2 2, 0 2, 2 0, 0 0))")) self.assertTrue(f.isValid()) f2 = QgsFeature(polygon_layer.fields()) f2.setAttributes([1]) f2.setGeometry( QgsGeometry.fromWkt( "POLYGON((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))" ) ) self.assertTrue(f2.isValid()) self.assertTrue(polygon_layer.addFeatures([f, f2])) polygon_layer.commitChanges() polygon_layer.rollBack() self.assertEqual(polygon_layer.featureCount(), 2) QgsProject.instance().addMapLayers([polygon_layer]) alg = self.registry.createAlgorithmById("qgis:checkvalidity") context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() self.assertIsNotNone(alg) parameters = {} parameters["INPUT_LAYER"] = polygon_layer.id() parameters["VALID_OUTPUT"] = "memory:" parameters["INVALID_OUTPUT"] = "memory:" parameters["ERROR_OUTPUT"] = "memory:" # QGIS method parameters["METHOD"] = 1 ok, results = execute(alg, parameters, context=context, feedback=feedback) self.assertTrue(ok) invalid_layer = QgsProcessingUtils.mapLayerFromString( results["INVALID_OUTPUT"], context ) self.assertEqual(invalid_layer.fields().names()[-1], "_errors") self.assertEqual(invalid_layer.featureCount(), 1) f = next(invalid_layer.getFeatures()) self.assertEqual( f.attributes(), [1, "segments 0 and 2 of line 0 intersect at 1, 1"] ) # GEOS method parameters["METHOD"] = 2 ok, results = execute(alg, parameters, context=context, feedback=feedback) self.assertTrue(ok) invalid_layer = QgsProcessingUtils.mapLayerFromString( results["INVALID_OUTPUT"], context ) self.assertEqual(invalid_layer.fields().names()[-1], "_errors") self.assertEqual(invalid_layer.featureCount(), 1) f = next(invalid_layer.getFeatures()) self.assertEqual(f.attributes(), [1, "Self-intersection"]) if __name__ == "__main__": unittest.main()