CheckValidityAlgorithm.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. """QGIS Unit tests for Processing CheckValidity algorithm.
  2. .. note:: This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. """
  7. __author__ = 'Alessandro Pasotti'
  8. __date__ = '2018-09'
  9. __copyright__ = 'Copyright 2018, The QGIS Project'
  10. from qgis.PyQt.QtCore import QCoreApplication, QVariant
  11. from qgis.core import (
  12. QgsFeature,
  13. QgsGeometry,
  14. QgsApplication,
  15. QgsMemoryProviderUtils,
  16. QgsWkbTypes,
  17. QgsField,
  18. QgsFields,
  19. QgsProcessingContext,
  20. QgsProcessingFeedback,
  21. QgsCoordinateReferenceSystem,
  22. QgsProject,
  23. QgsProcessingException,
  24. QgsProcessingUtils,
  25. QgsSettings
  26. )
  27. from processing.core.Processing import Processing
  28. from processing.gui.AlgorithmExecutor import execute
  29. import unittest
  30. from qgis.testing import start_app, QgisTestCase
  31. from qgis.PyQt.QtTest import QSignalSpy
  32. from qgis.analysis import QgsNativeAlgorithms
  33. start_app()
  34. class ConsoleFeedBack(QgsProcessingFeedback):
  35. def reportError(self, error, fatalError=False):
  36. print(error)
  37. class TestQgsProcessingCheckValidity(QgisTestCase):
  38. @classmethod
  39. def setUpClass(cls):
  40. """Run before all tests"""
  41. super().setUpClass()
  42. QCoreApplication.setOrganizationName("QGIS_Test")
  43. QCoreApplication.setOrganizationDomain(
  44. "QGIS_TestPyQgsProcessingCheckValidity.com")
  45. QCoreApplication.setApplicationName(
  46. "QGIS_TestPyQgsProcessingCheckValidity")
  47. QgsSettings().clear()
  48. Processing.initialize()
  49. cls.registry = QgsApplication.instance().processingRegistry()
  50. def _make_layer(self, layer_wkb_name):
  51. fields = QgsFields()
  52. wkb_type = getattr(QgsWkbTypes, layer_wkb_name)
  53. fields.append(QgsField('int_f', QVariant.Int))
  54. layer = QgsMemoryProviderUtils.createMemoryLayer(
  55. '%s_layer' % layer_wkb_name, fields, wkb_type, QgsCoordinateReferenceSystem("EPSG:4326"))
  56. self.assertTrue(layer.isValid())
  57. self.assertEqual(layer.wkbType(), wkb_type)
  58. return layer
  59. def test_check_validity(self):
  60. """Test that the output invalid contains the error reason"""
  61. polygon_layer = self._make_layer('Polygon')
  62. self.assertTrue(polygon_layer.startEditing())
  63. f = QgsFeature(polygon_layer.fields())
  64. f.setAttributes([1])
  65. # Flake!
  66. f.setGeometry(QgsGeometry.fromWkt(
  67. 'POLYGON ((0 0, 2 2, 0 2, 2 0, 0 0))'))
  68. self.assertTrue(f.isValid())
  69. f2 = QgsFeature(polygon_layer.fields())
  70. f2.setAttributes([1])
  71. f2.setGeometry(QgsGeometry.fromWkt(
  72. 'POLYGON((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))'))
  73. self.assertTrue(f2.isValid())
  74. self.assertTrue(polygon_layer.addFeatures([f, f2]))
  75. polygon_layer.commitChanges()
  76. polygon_layer.rollBack()
  77. self.assertEqual(polygon_layer.featureCount(), 2)
  78. QgsProject.instance().addMapLayers([polygon_layer])
  79. alg = self.registry.createAlgorithmById('qgis:checkvalidity')
  80. context = QgsProcessingContext()
  81. context.setProject(QgsProject.instance())
  82. feedback = ConsoleFeedBack()
  83. self.assertIsNotNone(alg)
  84. parameters = {}
  85. parameters['INPUT_LAYER'] = polygon_layer.id()
  86. parameters['VALID_OUTPUT'] = 'memory:'
  87. parameters['INVALID_OUTPUT'] = 'memory:'
  88. parameters['ERROR_OUTPUT'] = 'memory:'
  89. # QGIS method
  90. parameters['METHOD'] = 1
  91. ok, results = execute(
  92. alg, parameters, context=context, feedback=feedback)
  93. self.assertTrue(ok)
  94. invalid_layer = QgsProcessingUtils.mapLayerFromString(
  95. results['INVALID_OUTPUT'], context)
  96. self.assertEqual(invalid_layer.fields().names()[-1], '_errors')
  97. self.assertEqual(invalid_layer.featureCount(), 1)
  98. f = next(invalid_layer.getFeatures())
  99. self.assertEqual(f.attributes(), [
  100. 1, 'segments 0 and 2 of line 0 intersect at 1, 1'])
  101. # GEOS method
  102. parameters['METHOD'] = 2
  103. ok, results = execute(
  104. alg, parameters, context=context, feedback=feedback)
  105. self.assertTrue(ok)
  106. invalid_layer = QgsProcessingUtils.mapLayerFromString(
  107. results['INVALID_OUTPUT'], context)
  108. self.assertEqual(invalid_layer.fields().names()[-1], '_errors')
  109. self.assertEqual(invalid_layer.featureCount(), 1)
  110. f = next(invalid_layer.getFeatures())
  111. self.assertEqual(f.attributes(), [1, 'Self-intersection'])
  112. if __name__ == '__main__':
  113. unittest.main()