From de9e3ad8829ad735936f1ed775def64c42f248be Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 12 Jun 2025 11:08:30 +1000 Subject: [PATCH 01/10] Vertex tool test: correctly clear settings to start from stable environment (cherry picked from commit 20240870fbf0672ef359456e4817922937f6df50) --- tests/src/app/testqgsvertextool.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/src/app/testqgsvertextool.cpp b/tests/src/app/testqgsvertextool.cpp index 02b20b43948..0acb9335f3a 100644 --- a/tests/src/app/testqgsvertextool.cpp +++ b/tests/src/app/testqgsvertextool.cpp @@ -186,15 +186,19 @@ void TestQgsVertexTool::initTestCase() { qDebug() << "TestQgsVertexTool::initTestCase()"; // init QGIS's paths - true means that all path will be inited from prefix - QgsApplication::init(); - QgsApplication::initQgis(); - mQgisApp = new QgisApp(); // Set up the QSettings environment QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) ); QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) ); QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) ); + QgsApplication::init(); + QgsApplication::initQgis(); + + QgsSettings().clear(); + + mQgisApp = new QgisApp(); + mCanvas = new QgsMapCanvas(); mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:27700" ) ) ); From ea0321e200d43658798221c6f6de7596f3729a65 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 12 Jun 2025 11:10:00 +1000 Subject: [PATCH 02/10] Vertex tool test: don't rely on tests running in a certain order Instead re-setup layers before each test, and drop changes after each one (cherry picked from commit 14a3a5894cbf69a8c0e4b1117dfaaf20996dc735) --- tests/src/app/testqgsvertextool.cpp | 104 ++++++++++++++-------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/tests/src/app/testqgsvertextool.cpp b/tests/src/app/testqgsvertextool.cpp index 0acb9335f3a..1459b156bdd 100644 --- a/tests/src/app/testqgsvertextool.cpp +++ b/tests/src/app/testqgsvertextool.cpp @@ -60,7 +60,9 @@ class TestQgsVertexTool : public QObject TestQgsVertexTool(); private slots: - void initTestCase(); // will be called before the first testfunction is executed. + void initTestCase(); // will be called before the first testfunction is executed. + void init(); + void cleanup(); void cleanupTestCase(); // will be called after the last testfunction was executed. void testSelectVerticesByPolygon(); @@ -226,6 +228,37 @@ void TestQgsVertexTool::initTestCase() QVERIFY( mLayerCompoundCurve->isValid() ); QgsProject::instance()->addMapLayers( QList() << mLayerLine << mLayerMultiLine << mLayerPolygon << mLayerMultiPolygon << mLayerPoint << mLayerPointZ << mLayerLineZ << mLayerCompoundCurve ); + mCanvas->setFrameStyle( QFrame::NoFrame ); + mCanvas->resize( 512, 512 ); + mCanvas->setExtent( QgsRectangle( 0, 0, 8, 8 ) ); + mCanvas->show(); // to make the canvas resize + mCanvas->hide(); + QCOMPARE( mCanvas->mapSettings().outputSize(), QSize( 512, 512 ) ); + QCOMPARE( mCanvas->mapSettings().visibleExtent(), QgsRectangle( 0, 0, 8, 8 ) ); + + mCanvas->setLayers( QList() << mLayerLine << mLayerMultiLine << mLayerLineReprojected << mLayerPolygon << mLayerMultiPolygon << mLayerPoint << mLayerPointZ << mLayerLineZ << mLayerCompoundCurve ); + + QgsMapCanvasSnappingUtils *snappingUtils = new QgsMapCanvasSnappingUtils( mCanvas, this ); + mCanvas->setSnappingUtils( snappingUtils ); + + snappingUtils->locatorForLayer( mLayerLine )->init(); + snappingUtils->locatorForLayer( mLayerMultiLine )->init(); + snappingUtils->locatorForLayer( mLayerLineReprojected )->init(); + snappingUtils->locatorForLayer( mLayerPolygon )->init(); + snappingUtils->locatorForLayer( mLayerMultiPolygon )->init(); + snappingUtils->locatorForLayer( mLayerPoint )->init(); + snappingUtils->locatorForLayer( mLayerPointZ )->init(); + snappingUtils->locatorForLayer( mLayerLineZ )->init(); + snappingUtils->locatorForLayer( mLayerCompoundCurve )->init(); + + // create vertex tool + mVertexTool = new QgsVertexTool( mCanvas, mAdvancedDigitizingDockWidget ); + + mCanvas->setMapTool( mVertexTool ); +} + +void TestQgsVertexTool::init() +{ QgsFeature lineF1; lineF1.setGeometry( QgsGeometry::fromWkt( "LineString (2 1, 1 1, 1 3)" ) ); @@ -322,33 +355,26 @@ void TestQgsVertexTool::initTestCase() QCOMPARE( mLayerLineZ->undoStack()->index(), 3 ); QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 2 ); - mCanvas->setFrameStyle( QFrame::NoFrame ); - mCanvas->resize( 512, 512 ); - mCanvas->setExtent( QgsRectangle( 0, 0, 8, 8 ) ); - mCanvas->show(); // to make the canvas resize - mCanvas->hide(); - QCOMPARE( mCanvas->mapSettings().outputSize(), QSize( 512, 512 ) ); - QCOMPARE( mCanvas->mapSettings().visibleExtent(), QgsRectangle( 0, 0, 8, 8 ) ); - + QgsProject::instance()->setTopologicalEditing( false ); + mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:27700" ) ) ); mCanvas->setLayers( QList() << mLayerLine << mLayerMultiLine << mLayerLineReprojected << mLayerPolygon << mLayerMultiPolygon << mLayerPoint << mLayerPointZ << mLayerLineZ << mLayerCompoundCurve ); - QgsMapCanvasSnappingUtils *snappingUtils = new QgsMapCanvasSnappingUtils( mCanvas, this ); - mCanvas->setSnappingUtils( snappingUtils ); + QgsSnappingConfig cfg = mCanvas->snappingUtils()->config(); + cfg.setEnabled( false ); + mCanvas->snappingUtils()->setConfig( cfg ); +} - snappingUtils->locatorForLayer( mLayerLine )->init(); - snappingUtils->locatorForLayer( mLayerMultiLine )->init(); - snappingUtils->locatorForLayer( mLayerLineReprojected )->init(); - snappingUtils->locatorForLayer( mLayerPolygon )->init(); - snappingUtils->locatorForLayer( mLayerMultiPolygon )->init(); - snappingUtils->locatorForLayer( mLayerPoint )->init(); - snappingUtils->locatorForLayer( mLayerPointZ )->init(); - snappingUtils->locatorForLayer( mLayerLineZ )->init(); - snappingUtils->locatorForLayer( mLayerCompoundCurve )->init(); - - // create vertex tool - mVertexTool = new QgsVertexTool( mCanvas, mAdvancedDigitizingDockWidget ); - - mCanvas->setMapTool( mVertexTool ); +void TestQgsVertexTool::cleanup() +{ + mLayerLine->rollBack(); + mLayerMultiLine->rollBack(); + mLayerLineReprojected->rollBack(); + mLayerPolygon->rollBack(); + mLayerMultiPolygon->rollBack(); + mLayerPoint->rollBack(); + mLayerPointZ->rollBack(); + mLayerLineZ->rollBack(); + mLayerCompoundCurve->rollBack(); } //runs after all tests @@ -365,7 +391,6 @@ void TestQgsVertexTool::testTopologicalEditingMoveVertexZ() QCOMPARE( mLayerLineZ->undoStack()->index(), 3 ); QCOMPARE( mLayerLineZ->featureCount(), ( long ) 3 ); - const bool topologicalEditing = QgsProject::instance()->topologicalEditing(); QgsProject::instance()->setTopologicalEditing( true ); QgsSnappingConfig cfg = mCanvas->snappingUtils()->config(); cfg.setMode( Qgis::SnappingMode::AllLayers ); @@ -380,7 +405,6 @@ void TestQgsVertexTool::testTopologicalEditingMoveVertexZ() QCOMPARE( mLayerLineZ->getFeature( mFidLineZF1 ).geometry().asWkt(), QString( "LineString Z (5 5 1, 5 7 5, 7 5 1)" ) ); QCOMPARE( mLayerLineZ->getFeature( mFidLineZF2 ).geometry().asWkt(), QString( "LineString Z (5 7 5, 7 7 10)" ) ); - QgsProject::instance()->setTopologicalEditing( topologicalEditing ); mLayerLineZ->undoStack()->undo(); cfg.setEnabled( false ); mCanvas->snappingUtils()->setConfig( cfg ); @@ -396,7 +420,6 @@ void TestQgsVertexTool::testTopologicalEditingMoveVertexOnSegmentZ() QgsSettingsRegistryCore::settingsDigitizingDefaultZValue->setValue( 333 ); - const bool topologicalEditing = QgsProject::instance()->topologicalEditing(); QgsProject::instance()->setTopologicalEditing( true ); QgsSnappingConfig cfg = mCanvas->snappingUtils()->config(); cfg.setMode( Qgis::SnappingMode::AllLayers ); @@ -411,7 +434,6 @@ void TestQgsVertexTool::testTopologicalEditingMoveVertexOnSegmentZ() QCOMPARE( mLayerLineZ->getFeature( mFidLineZF1 ).geometry().asWkt(), QString( "LineString Z (5 5 1, 6 7 7.5, 7 5 1)" ) ); QCOMPARE( mLayerLineZ->getFeature( mFidLineZF2 ).geometry().asWkt(), QString( "LineString Z (5 7 5, 6 7 7.5, 7 7 10)" ) ); - QgsProject::instance()->setTopologicalEditing( topologicalEditing ); // Two undo steps, one for the vertex move, one for the topological point mLayerLineZ->undoStack()->undo(); mLayerLineZ->undoStack()->undo(); @@ -426,7 +448,6 @@ void TestQgsVertexTool::testTopologicalEditingMoveVertexOnIntersectionZ() { QgsSettingsRegistryCore::settingsDigitizingDefaultZValue->setValue( 333 ); - const bool topologicalEditing = QgsProject::instance()->topologicalEditing(); QgsProject::instance()->setTopologicalEditing( true ); QgsSnappingConfig cfg = mCanvas->snappingUtils()->config(); cfg.setMode( Qgis::SnappingMode::AllLayers ); @@ -444,7 +465,6 @@ void TestQgsVertexTool::testTopologicalEditingMoveVertexOnIntersectionZ() QCOMPARE( mLayerLineZ->getFeature( mFidLineZF1 ).geometry().asWkt(), QString( "LineString Z (5 5 1, 5.5 5.5 5, 6 6 1, 7 5 1)" ) ); QCOMPARE( mLayerLineZ->getFeature( mFidLineZF3 ).geometry().asWkt(), QString( "LineString Z (5.5 5.5 5, 7 5.5 10)" ) ); - QgsProject::instance()->setTopologicalEditing( topologicalEditing ); // Two undo steps, one for the vertex move, one for the topological point mLayerLineZ->undoStack()->undo(); mLayerLineZ->undoStack()->undo(); @@ -466,7 +486,6 @@ void TestQgsVertexTool::testTopologicalEditingMoveVerticesOnSegmentZ() QCOMPARE( mLayerLineZ->featureCount(), ( long ) 4 ); // Activates topological editing - const bool topologicalEditing = QgsProject::instance()->topologicalEditing(); QgsProject::instance()->setTopologicalEditing( true ); // And snapping @@ -493,7 +512,6 @@ void TestQgsVertexTool::testTopologicalEditingMoveVerticesOnSegmentZ() // Undo changes mLayerLineZ->deleteFeature( linez.id() ); - QgsProject::instance()->setTopologicalEditing( topologicalEditing ); mLayerLineZ->undoStack()->undo(); mLayerLineZ->undoStack()->undo(); mLayerLineZ->undoStack()->undo(); @@ -1041,8 +1059,6 @@ void TestQgsVertexTool::testMoveVertexTopo() QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) ); QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) ); - - QgsProject::instance()->setTopologicalEditing( false ); } void TestQgsVertexTool::testDeleteVertexTopo() @@ -1070,8 +1086,6 @@ void TestQgsVertexTool::testDeleteVertexTopo() QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) ); QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) ); - - QgsProject::instance()->setTopologicalEditing( false ); } void TestQgsVertexTool::testAddVertexTopo() @@ -1101,8 +1115,6 @@ void TestQgsVertexTool::testAddVertexTopo() mLayerPolygon->undoStack()->undo(); QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) ); - - QgsProject::instance()->setTopologicalEditing( false ); } void TestQgsVertexTool::testMoveEdgeTopo() @@ -1158,8 +1170,6 @@ void TestQgsVertexTool::testMoveEdgeTopo() mLayerPolygon->undoStack()->undo(); QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) ); - - QgsProject::instance()->setTopologicalEditing( false ); } void TestQgsVertexTool::testAddVertexTopoFirstSegment() @@ -1179,8 +1189,6 @@ void TestQgsVertexTool::testAddVertexTopoFirstSegment() mLayerPolygon->undoStack()->undo(); QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) ); - - QgsProject::instance()->setTopologicalEditing( false ); } void TestQgsVertexTool::testAddVertexTopoMultipleLayers() @@ -1194,7 +1202,6 @@ void TestQgsVertexTool::testAddVertexTopoMultipleLayers() QVERIFY( resAdd ); const QgsFeatureId fTmpId = fTmp.id(); - const bool topologicalEditing = QgsProject::instance()->topologicalEditing(); QgsProject::instance()->setTopologicalEditing( true ); QgsSnappingConfig cfg = mCanvas->snappingUtils()->config(); cfg.setMode( Qgis::SnappingMode::AllLayers ); @@ -1235,7 +1242,6 @@ void TestQgsVertexTool::testAddVertexTopoMultipleLayers() QCOMPARE( mLayerPolygon->undoStack()->index(), 1 ); - QgsProject::instance()->setTopologicalEditing( topologicalEditing ); cfg.setEnabled( false ); mCanvas->snappingUtils()->setConfig( cfg ); } @@ -1387,7 +1393,6 @@ void TestQgsVertexTool::testAvoidIntersections() QCOMPARE( mLayerPolygon->featureCount(), ( long ) 1 ); - QgsProject::instance()->setTopologicalEditing( false ); QgsProject::instance()->setAvoidIntersectionsMode( mode ); } @@ -1479,7 +1484,6 @@ void TestQgsVertexTool::testActiveLayerPriority() mCanvas->setCurrentLayer( nullptr ); // get rid of the temporary layer - mCanvas->setLayers( oldMapLayers ); QgsProject::instance()->removeMapLayer( layerLine2 ); } @@ -1650,15 +1654,13 @@ void TestQgsVertexTool::testMoveVertexTopoOtherMapCrs() // test moving of vertices of two features at once QgsProject::instance()->setTopologicalEditing( true ); - QgsCoordinateReferenceSystem prevCrs = QgsProject::instance()->crs(); - QgsCoordinateReferenceSystem tmpCrs = QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ); // move linestring vertex to connect with polygon at point (7, 1) mouseClick( 2, 1, Qt::LeftButton ); mouseClick( 7, 1, Qt::LeftButton ); // change CRS so that the map canvas and the layers CRSs are different - mCanvas->setDestinationCrs( tmpCrs ); + mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ) ); mCanvas->snappingUtils()->locatorForLayer( mLayerLine )->init(); mCanvas->snappingUtils()->locatorForLayer( mLayerPolygon )->init(); @@ -1683,8 +1685,6 @@ void TestQgsVertexTool::testMoveVertexTopoOtherMapCrs() // back to the original state QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) ); QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) ); - mCanvas->setDestinationCrs( prevCrs ); - QgsProject::instance()->setTopologicalEditing( false ); } QGSTEST_MAIN( TestQgsVertexTool ) From 7caa08b2c39765a58f166db9980c78a84e3e2aeb Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 12 Jun 2025 11:20:37 +1000 Subject: [PATCH 03/10] Check that test starts from a known state (cherry picked from commit c11f155a492694a2fbc512b954a17a53f6e1c228) --- tests/src/app/testqgsvertextool.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/src/app/testqgsvertextool.cpp b/tests/src/app/testqgsvertextool.cpp index 1459b156bdd..6c65a9e10fd 100644 --- a/tests/src/app/testqgsvertextool.cpp +++ b/tests/src/app/testqgsvertextool.cpp @@ -1651,6 +1651,9 @@ void TestQgsVertexTool::testSelectVerticesByPolygon() void TestQgsVertexTool::testMoveVertexTopoOtherMapCrs() { + QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry().asWkt( 2 ), "LineString (2 1, 1 1, 1 3)" ); + QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry().asWkt( 2 ), "Polygon ((4 1, 7 1, 7 4, 4 4, 4 1))" ); + // test moving of vertices of two features at once QgsProject::instance()->setTopologicalEditing( true ); From 3d9ac99b9f69a1d6feefed76540e16ed72cd55d6 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 12 Jun 2025 11:37:29 +1000 Subject: [PATCH 04/10] Force use of non-grid shift transform to add test stability (cherry picked from commit ac1ed7fbab2de7f38adaf4aa62f0b70e6d7df7b5) --- tests/src/app/testqgsvertextool.cpp | 39 +++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/tests/src/app/testqgsvertextool.cpp b/tests/src/app/testqgsvertextool.cpp index 6c65a9e10fd..5fc47a18c22 100644 --- a/tests/src/app/testqgsvertextool.cpp +++ b/tests/src/app/testqgsvertextool.cpp @@ -153,6 +153,7 @@ class TestQgsVertexTool : public QObject } private: + QgsCoordinateReferenceSystem mFake27700; QgsMapCanvas *mCanvas = nullptr; QgisApp *mQgisApp = nullptr; QgsAdvancedDigitizingDockWidget *mAdvancedDigitizingDockWidget = nullptr; @@ -199,33 +200,48 @@ void TestQgsVertexTool::initTestCase() QgsSettings().clear(); + // EPSG:27700 was a silly choice for these tests, as the transformations rely on the presence of a grid shift + // file which may or may not be present on some platforms :'( + + // Fake a similar CRS which can't use grid based transforms ;) + mFake27700 = QgsCoordinateReferenceSystem::fromProj( "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=4000.0000001 +y_0=-100000 +ellps=airy +units=m +no_defs" ); + QCOMPARE( mFake27700.authid(), QString() ); + mQgisApp = new QgisApp(); mCanvas = new QgsMapCanvas(); - mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:27700" ) ) ); + mCanvas->setDestinationCrs( mFake27700 ); mAdvancedDigitizingDockWidget = new QgsAdvancedDigitizingDockWidget( mCanvas ); // make testing layers - mLayerLine = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:27700" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) ); + mLayerLine = new QgsVectorLayer( QStringLiteral( "LineString?" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) ); + mLayerLine->setCrs( mFake27700 ); QVERIFY( mLayerLine->isValid() ); - mLayerMultiLine = new QgsVectorLayer( QStringLiteral( "MultiLineString?crs=EPSG:27700" ), QStringLiteral( "layer multiline" ), QStringLiteral( "memory" ) ); + mLayerMultiLine = new QgsVectorLayer( QStringLiteral( "MultiLineString?" ), QStringLiteral( "layer multiline" ), QStringLiteral( "memory" ) ); + mLayerMultiLine->setCrs( mFake27700 ); QVERIFY( mLayerMultiLine->isValid() ); mLayerLineReprojected = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:3857" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerLineReprojected->isValid() ); - mLayerPolygon = new QgsVectorLayer( QStringLiteral( "Polygon?crs=EPSG:27700" ), QStringLiteral( "layer polygon" ), QStringLiteral( "memory" ) ); + mLayerPolygon = new QgsVectorLayer( QStringLiteral( "Polygon?" ), QStringLiteral( "layer polygon" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerPolygon->isValid() ); - mLayerMultiPolygon = new QgsVectorLayer( QStringLiteral( "MultiPolygon?crs=EPSG:27700" ), QStringLiteral( "layer multipolygon" ), QStringLiteral( "memory" ) ); + mLayerPolygon->setCrs( mFake27700 ); + mLayerMultiPolygon = new QgsVectorLayer( QStringLiteral( "MultiPolygon?" ), QStringLiteral( "layer multipolygon" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerMultiPolygon->isValid() ); - mLayerPoint = new QgsVectorLayer( QStringLiteral( "Point?crs=EPSG:27700" ), QStringLiteral( "layer point" ), QStringLiteral( "memory" ) ); + mLayerMultiPolygon->setCrs( mFake27700 ); + mLayerPoint = new QgsVectorLayer( QStringLiteral( "Point?" ), QStringLiteral( "layer point" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerPoint->isValid() ); - mLayerPointZ = new QgsVectorLayer( QStringLiteral( "PointZ?crs=EPSG:27700" ), QStringLiteral( "layer pointz" ), QStringLiteral( "memory" ) ); + mLayerPoint->setCrs( mFake27700 ); + mLayerPointZ = new QgsVectorLayer( QStringLiteral( "PointZ?" ), QStringLiteral( "layer pointz" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerPointZ->isValid() ); - mLayerLineZ = new QgsVectorLayer( QStringLiteral( "LineStringZ?crs=EPSG:27700" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) ); + mLayerPointZ->setCrs( mFake27700 ); + mLayerLineZ = new QgsVectorLayer( QStringLiteral( "LineStringZ?" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerLineZ->isValid() ); - mLayerCompoundCurve = new QgsVectorLayer( QStringLiteral( "CompoundCurve?crs=27700" ), QStringLiteral( "layer compound curve" ), QStringLiteral( "memory" ) ); + mLayerLineZ->setCrs( mFake27700 ); + mLayerCompoundCurve = new QgsVectorLayer( QStringLiteral( "CompoundCurve?" ), QStringLiteral( "layer compound curve" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerCompoundCurve->isValid() ); + mLayerCompoundCurve->setCrs( mFake27700 ); QgsProject::instance()->addMapLayers( QList() << mLayerLine << mLayerMultiLine << mLayerPolygon << mLayerMultiPolygon << mLayerPoint << mLayerPointZ << mLayerLineZ << mLayerCompoundCurve ); mCanvas->setFrameStyle( QFrame::NoFrame ); @@ -356,7 +372,7 @@ void TestQgsVertexTool::init() QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 2 ); QgsProject::instance()->setTopologicalEditing( false ); - mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:27700" ) ) ); + mCanvas->setDestinationCrs( mFake27700 ); mCanvas->setLayers( QList() << mLayerLine << mLayerMultiLine << mLayerLineReprojected << mLayerPolygon << mLayerMultiPolygon << mLayerPoint << mLayerPointZ << mLayerLineZ << mLayerCompoundCurve ); QgsSnappingConfig cfg = mCanvas->snappingUtils()->config(); @@ -1443,7 +1459,8 @@ void TestQgsVertexTool::testActiveLayerPriority() // check that features from current layer get priority when picking points // create a temporary line layer that has a common vertex with existing line layer at (1, 1) - QgsVectorLayer *layerLine2 = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:27700" ), QStringLiteral( "layer line 2" ), QStringLiteral( "memory" ) ); + QgsVectorLayer *layerLine2 = new QgsVectorLayer( QStringLiteral( "LineString?" ), QStringLiteral( "layer line 2" ), QStringLiteral( "memory" ) ); + layerLine2->setCrs( mFake27700 ); QVERIFY( layerLine2->isValid() ); QgsPolylineXY line1; line1 << QgsPointXY( 0, 1 ) << QgsPointXY( 1, 1 ) << QgsPointXY( 1, 0 ); From 6f4dc82432fab62e66fbff85f2eedbbffa7c64f6 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 3 Sep 2025 10:54:10 +1000 Subject: [PATCH 05/10] Make tests completely independant, by recreating all layers and tool between tests (cherry picked from commit 73a824582c044dc69011b6fdf271a9d15cb866e4) --- tests/src/app/testqgsvertextool.cpp | 93 +++++++++++++++-------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/tests/src/app/testqgsvertextool.cpp b/tests/src/app/testqgsvertextool.cpp index 5fc47a18c22..962100b9b14 100644 --- a/tests/src/app/testqgsvertextool.cpp +++ b/tests/src/app/testqgsvertextool.cpp @@ -158,15 +158,15 @@ class TestQgsVertexTool : public QObject QgisApp *mQgisApp = nullptr; QgsAdvancedDigitizingDockWidget *mAdvancedDigitizingDockWidget = nullptr; QgsVertexTool *mVertexTool = nullptr; - QgsVectorLayer *mLayerLine = nullptr; - QgsVectorLayer *mLayerMultiLine = nullptr; - QgsVectorLayer *mLayerPolygon = nullptr; - QgsVectorLayer *mLayerMultiPolygon = nullptr; - QgsVectorLayer *mLayerPoint = nullptr; - QgsVectorLayer *mLayerPointZ = nullptr; - QgsVectorLayer *mLayerLineZ = nullptr; - QgsVectorLayer *mLayerCompoundCurve = nullptr; - QgsVectorLayer *mLayerLineReprojected = nullptr; + QPointer< QgsVectorLayer > mLayerLine; + QPointer< QgsVectorLayer > mLayerMultiLine; + QPointer< QgsVectorLayer > mLayerPolygon; + QPointer< QgsVectorLayer > mLayerMultiPolygon; + QPointer< QgsVectorLayer > mLayerPoint; + QPointer< QgsVectorLayer > mLayerPointZ; + QPointer< QgsVectorLayer > mLayerLineZ; + QPointer< QgsVectorLayer > mLayerCompoundCurve; + QPointer< QgsVectorLayer > mLayerLineReprojected; QgsFeatureId mFidLineZF1 = 0; QgsFeatureId mFidLineZF2 = 0; QgsFeatureId mFidLineZF3 = 0; @@ -208,13 +208,10 @@ void TestQgsVertexTool::initTestCase() QCOMPARE( mFake27700.authid(), QString() ); mQgisApp = new QgisApp(); +} - mCanvas = new QgsMapCanvas(); - - mCanvas->setDestinationCrs( mFake27700 ); - - mAdvancedDigitizingDockWidget = new QgsAdvancedDigitizingDockWidget( mCanvas ); - +void TestQgsVertexTool::init() +{ // make testing layers mLayerLine = new QgsVectorLayer( QStringLiteral( "LineString?" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) ); mLayerLine->setCrs( mFake27700 ); @@ -244,37 +241,7 @@ void TestQgsVertexTool::initTestCase() mLayerCompoundCurve->setCrs( mFake27700 ); QgsProject::instance()->addMapLayers( QList() << mLayerLine << mLayerMultiLine << mLayerPolygon << mLayerMultiPolygon << mLayerPoint << mLayerPointZ << mLayerLineZ << mLayerCompoundCurve ); - mCanvas->setFrameStyle( QFrame::NoFrame ); - mCanvas->resize( 512, 512 ); - mCanvas->setExtent( QgsRectangle( 0, 0, 8, 8 ) ); - mCanvas->show(); // to make the canvas resize - mCanvas->hide(); - QCOMPARE( mCanvas->mapSettings().outputSize(), QSize( 512, 512 ) ); - QCOMPARE( mCanvas->mapSettings().visibleExtent(), QgsRectangle( 0, 0, 8, 8 ) ); - mCanvas->setLayers( QList() << mLayerLine << mLayerMultiLine << mLayerLineReprojected << mLayerPolygon << mLayerMultiPolygon << mLayerPoint << mLayerPointZ << mLayerLineZ << mLayerCompoundCurve ); - - QgsMapCanvasSnappingUtils *snappingUtils = new QgsMapCanvasSnappingUtils( mCanvas, this ); - mCanvas->setSnappingUtils( snappingUtils ); - - snappingUtils->locatorForLayer( mLayerLine )->init(); - snappingUtils->locatorForLayer( mLayerMultiLine )->init(); - snappingUtils->locatorForLayer( mLayerLineReprojected )->init(); - snappingUtils->locatorForLayer( mLayerPolygon )->init(); - snappingUtils->locatorForLayer( mLayerMultiPolygon )->init(); - snappingUtils->locatorForLayer( mLayerPoint )->init(); - snappingUtils->locatorForLayer( mLayerPointZ )->init(); - snappingUtils->locatorForLayer( mLayerLineZ )->init(); - snappingUtils->locatorForLayer( mLayerCompoundCurve )->init(); - - // create vertex tool - mVertexTool = new QgsVertexTool( mCanvas, mAdvancedDigitizingDockWidget ); - - mCanvas->setMapTool( mVertexTool ); -} - -void TestQgsVertexTool::init() -{ QgsFeature lineF1; lineF1.setGeometry( QgsGeometry::fromWkt( "LineString (2 1, 1 1, 1 3)" ) ); @@ -372,9 +339,41 @@ void TestQgsVertexTool::init() QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 2 ); QgsProject::instance()->setTopologicalEditing( false ); + + mCanvas = new QgsMapCanvas(); + mCanvas->setDestinationCrs( mFake27700 ); + + mAdvancedDigitizingDockWidget = new QgsAdvancedDigitizingDockWidget( mCanvas ); + + mCanvas->setFrameStyle( QFrame::NoFrame ); + mCanvas->resize( 512, 512 ); + mCanvas->setExtent( QgsRectangle( 0, 0, 8, 8 ) ); + mCanvas->show(); // to make the canvas resize + mCanvas->hide(); + QCOMPARE( mCanvas->mapSettings().outputSize(), QSize( 512, 512 ) ); + QCOMPARE( mCanvas->mapSettings().visibleExtent(), QgsRectangle( 0, 0, 8, 8 ) ); + mCanvas->setLayers( QList() << mLayerLine << mLayerMultiLine << mLayerLineReprojected << mLayerPolygon << mLayerMultiPolygon << mLayerPoint << mLayerPointZ << mLayerLineZ << mLayerCompoundCurve ); + QgsMapCanvasSnappingUtils *snappingUtils = new QgsMapCanvasSnappingUtils( mCanvas, this ); + mCanvas->setSnappingUtils( snappingUtils ); + + snappingUtils->locatorForLayer( mLayerLine )->init(); + snappingUtils->locatorForLayer( mLayerMultiLine )->init(); + snappingUtils->locatorForLayer( mLayerLineReprojected )->init(); + snappingUtils->locatorForLayer( mLayerPolygon )->init(); + snappingUtils->locatorForLayer( mLayerMultiPolygon )->init(); + snappingUtils->locatorForLayer( mLayerPoint )->init(); + snappingUtils->locatorForLayer( mLayerPointZ )->init(); + snappingUtils->locatorForLayer( mLayerLineZ )->init(); + snappingUtils->locatorForLayer( mLayerCompoundCurve )->init(); + + // create vertex tool + mVertexTool = new QgsVertexTool( mCanvas, mAdvancedDigitizingDockWidget ); + + mCanvas->setMapTool( mVertexTool ); + QgsSnappingConfig cfg = mCanvas->snappingUtils()->config(); cfg.setEnabled( false ); mCanvas->snappingUtils()->setConfig( cfg ); @@ -391,6 +390,8 @@ void TestQgsVertexTool::cleanup() mLayerPointZ->rollBack(); mLayerLineZ->rollBack(); mLayerCompoundCurve->rollBack(); + + QgsProject::instance()->clear(); } //runs after all tests @@ -549,6 +550,8 @@ void TestQgsVertexTool::testMoveVertex() mouseClick( 2, 1, Qt::LeftButton ); mouseClick( 2, 2, Qt::LeftButton ); + QCOMPARE( mLayerLine->undoStack()->count(), 2 ); + QCOMPARE( mLayerLine->undoStack()->index(), 2 ); QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 2, 1 1, 1 3)" ) ); From 760076058e4269291b3a44668c9ddc4961d351cd Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 12 Jun 2025 12:10:43 +1000 Subject: [PATCH 06/10] Fix test I'm not sure how this ever passed, but it must have relied on some esoteric combination of platform specific transformations which caused a 3 vertex linestring to be represented as a 2 vertex one (cherry picked from commit d5c95c387e5baca8b62cd09ad9ceb21bfe33da9c) --- tests/src/app/testqgsvertextool.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/src/app/testqgsvertextool.cpp b/tests/src/app/testqgsvertextool.cpp index 962100b9b14..6e5fc0cb60d 100644 --- a/tests/src/app/testqgsvertextool.cpp +++ b/tests/src/app/testqgsvertextool.cpp @@ -1009,6 +1009,9 @@ void TestQgsVertexTool::testConvertVertex() void TestQgsVertexTool::testMoveMultipleVertices() { + QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (2 1, 1 1, 1 3)" ) ); + QCOMPARE( mLayerLineReprojected->getFeature( mFidLineF13857 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (-228837 6428900, -228838 6428900, -228838 6428903)" ) ); + // select two vertices mousePress( 0.5, 0.5, Qt::LeftButton ); mouseMove( 1.5, 3.5 ); @@ -1022,16 +1025,20 @@ void TestQgsVertexTool::testMoveMultipleVertices() mouseClick( 8, 8, Qt::LeftButton ); QCOMPARE( mLayerLine->undoStack()->index(), 2 ); - QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 0 0, 0 2)" ) ); + QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (2 1, 0 0, 0 2)" ) ); + QCOMPARE( mLayerLineReprojected->getFeature( mFidLineF13857 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (-228837 6428900, -228840 6428899, -228840 6428902)" ) ); mLayerLine->undoStack()->undo(); QCOMPARE( mLayerLine->undoStack()->index(), 1 ); + QCOMPARE( mLayerLineReprojected->undoStack()->index(), 2 ); + QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (2 1, 1 1, 1 3)" ) ); + QCOMPARE( mLayerLineReprojected->getFeature( mFidLineF13857 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (-228837 6428900, -228840 6428899, -228840 6428902)" ) ); QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) ); QCOMPARE( mLayerLineReprojected->getFeature( mFidLineF13857 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (-841256 6405990, -841259 6405988)" ) ); mLayerLineReprojected->undoStack()->undo(); - QCOMPARE( mLayerLineReprojected->getFeature( mFidLineF13857 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (-841256 6405990, -841258 6405990)" ) ); + QCOMPARE( mLayerLineReprojected->getFeature( mFidLineF13857 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (-228837 6428900, -228838 6428900, -228838 6428903)" ) ); } void TestQgsVertexTool::testMoveMultipleVertices2() From cfb5b497f9d951318c4a7b8935b86ce98d9407ee Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 12 Jun 2025 13:55:53 +1000 Subject: [PATCH 07/10] Fix warning (cherry picked from commit 00bc951cc3b80ee1b541e2050b71af0411caa59c) --- tests/src/app/testqgsvertextool.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/src/app/testqgsvertextool.cpp b/tests/src/app/testqgsvertextool.cpp index 6e5fc0cb60d..cbdde67c006 100644 --- a/tests/src/app/testqgsvertextool.cpp +++ b/tests/src/app/testqgsvertextool.cpp @@ -1481,7 +1481,6 @@ void TestQgsVertexTool::testActiveLayerPriority() const QgsFeatureId fidLineF1 = lineF1.id(); QCOMPARE( layerLine2->featureCount(), ( long ) 1 ); QgsProject::instance()->addMapLayer( layerLine2 ); - QList oldMapLayers = mCanvas->layers(); mCanvas->setLayers( QList() << mLayerLine << mLayerPolygon << mLayerPoint << mLayerCompoundCurve << layerLine2 ); // make one layer active and check its vertex is used From 4ac233733ffb6fcb24462f41142aa9c71711ab92 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 3 Sep 2025 11:01:46 +1000 Subject: [PATCH 08/10] Memory safety, fix leak (cherry picked from commit 93d5bd2ce6e0087471a3110c3e1ac22813d143a8) --- src/app/vertextool/qgsvertextool.cpp | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/app/vertextool/qgsvertextool.cpp b/src/app/vertextool/qgsvertextool.cpp index 3c49ecd57b8..a958e6fb3b3 100644 --- a/src/app/vertextool/qgsvertextool.cpp +++ b/src/app/vertextool/qgsvertextool.cpp @@ -250,7 +250,7 @@ QgsVertexTool::QgsVertexTool( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWid { setAdvancedDigitizingAllowed( false ); - mSnapIndicator.reset( new QgsSnapIndicator( canvas ) ); + mSnapIndicator = std::make_unique< QgsSnapIndicator >( canvas ); mEdgeCenterMarker = new QgsVertexMarker( canvas ); mEdgeCenterMarker->setIconType( QgsVertexMarker::ICON_CROSS ); @@ -487,7 +487,7 @@ void QgsVertexTool::cadCanvasPressEvent( QgsMapMouseEvent *e ) // the user may have started dragging a rect to select vertices if ( !mDraggingVertex && !mDraggingEdge ) - mSelectionRubberBandStartPos.reset( new QPoint( e->pos() ) ); + mSelectionRubberBandStartPos = std::make_unique< QPoint >( e->pos() ); } } @@ -795,7 +795,7 @@ void QgsVertexTool::canvasDoubleClickEvent( QgsMapMouseEvent *e ) if ( !m.hasEdge() ) return; - mNewVertexFromDoubleClick.reset( new QgsPointLocator::Match( m ) ); + mNewVertexFromDoubleClick = std::make_unique< QgsPointLocator::Match >( m ); } void QgsVertexTool::removeTemporaryRubberBands() @@ -932,7 +932,7 @@ QgsPointLocator::Match QgsVertexTool::snapToEditableLayer( QgsMapMouseEvent *e ) snapUtils->setConfig( oldConfig ); - mLastSnap.reset( new QgsPointLocator::Match( m ) ); + mLastSnap = std::make_unique< QgsPointLocator::Match >( m ); return m; } @@ -985,7 +985,7 @@ QgsPointLocator::Match QgsVertexTool::snapToPolygonInterior( QgsMapMouseEvent *e // if we don't have anything in the last snap, keep the area match if ( !mLastSnap && m.isValid() ) { - mLastSnap.reset( new QgsPointLocator::Match( m ) ); + mLastSnap = std::make_unique< QgsPointLocator::Match >( m ); } return m; @@ -1066,7 +1066,7 @@ void QgsVertexTool::tryToSelectFeature( QgsMapMouseEvent *e ) m = snapToPolygonInterior( e ); } - mLockedFeatureAlternatives.reset( new LockedFeatureAlternatives ); + mLockedFeatureAlternatives = std::make_unique< LockedFeatureAlternatives >(); mLockedFeatureAlternatives->screenPoint = e->pos(); mLockedFeatureAlternatives->index = -1; if ( m.isValid() ) @@ -1203,8 +1203,8 @@ void QgsVertexTool::mouseMoveNotDragging( QgsMapMouseEvent *e ) // so user can possibly add a new vertex at the end if ( isMatchAtEndpoint( m ) ) { - mMouseAtEndpoint.reset( new Vertex( m.layer(), m.featureId(), m.vertexIndex() ) ); - mEndpointMarkerCenter.reset( new QgsPointXY( positionForEndpointMarker( m ) ) ); + mMouseAtEndpoint = std::make_unique< Vertex >( m.layer(), m.featureId(), m.vertexIndex() ); + mEndpointMarkerCenter = std::make_unique< QgsPointXY >( positionForEndpointMarker( m ) ); mEndpointMarker->setCenter( *mEndpointMarkerCenter ); mEndpointMarker->setColor( Qt::gray ); mEndpointMarker->setVisible( true ); @@ -1759,7 +1759,7 @@ void QgsVertexTool::startDraggingMoveVertex( const QgsPointLocator::Match &m ) QgsGeometry geom = cachedGeometry( m.layer(), m.featureId() ); // start dragging of snapped point of current layer - mDraggingVertex.reset( new Vertex( m.layer(), m.featureId(), m.vertexIndex() ) ); + mDraggingVertex = std::make_unique< Vertex >( m.layer(), m.featureId(), m.vertexIndex() ); mDraggingVertexType = MovingVertex; mDraggingExtraVertices.clear(); mDraggingExtraVerticesOffset.clear(); @@ -1919,7 +1919,7 @@ void QgsVertexTool::startDraggingAddVertex( const QgsPointLocator::Match &m ) // activate advanced digitizing dock setAdvancedDigitizingAllowed( true ); - mDraggingVertex.reset( new Vertex( m.layer(), m.featureId(), m.vertexIndex() + 1 ) ); + mDraggingVertex = std::make_unique< Vertex >( m.layer(), m.featureId(), m.vertexIndex() + 1 ); mDraggingVertexType = AddingVertex; mDraggingExtraVertices.clear(); mDraggingExtraVerticesOffset.clear(); @@ -1973,7 +1973,7 @@ void QgsVertexTool::startDraggingAddVertexAtEndpoint( const QgsPointXY &mapPoint // activate advanced digitizing dock setAdvancedDigitizingAllowed( true ); - mDraggingVertex.reset( new Vertex( mMouseAtEndpoint->layer, mMouseAtEndpoint->fid, mMouseAtEndpoint->vertexId ) ); + mDraggingVertex = std::make_unique< Vertex >( mMouseAtEndpoint->layer, mMouseAtEndpoint->fid, mMouseAtEndpoint->vertexId ); mDraggingVertexType = AddingEndpoint; mDraggingExtraVertices.clear(); mDraggingExtraVerticesOffset.clear(); @@ -2135,7 +2135,7 @@ void QgsVertexTool::moveVertex( const QgsPointXY &mapPoint, const QgsPointLocato return; } - QgsAbstractGeometry *geomTmp = geom.constGet()->clone(); + std::unique_ptr< QgsAbstractGeometry > geomTmp( geom.constGet()->clone() ); // If moving point is not 3D but destination yes, check if it can be promoted if ( layerPoint.is3D() && !geomTmp->is3D() && QgsWkbTypes::hasZ( dragLayer->wkbType() ) ) @@ -2185,10 +2185,10 @@ void QgsVertexTool::moveVertex( const QgsPointXY &mapPoint, const QgsPointLocato } } - geom.set( geomTmp ); + geom = QgsGeometry( std::move( geomTmp ) ); VertexEdits edits; // dict { layer : { fid : geom } } - edits[dragLayer][dragFid] = VertexEdit( geom, geomTmp->vertexAt( vid ) ); + edits[dragLayer][dragFid] = VertexEdit( geom, geom.get()->vertexAt( vid ) ); addExtraVerticesToEdits( edits, mapPoint, dragLayer, layerPoint ); @@ -2276,7 +2276,7 @@ void QgsVertexTool::moveVertex( const QgsPointXY &mapPoint, const QgsPointLocato if ( mMouseAtEndpoint->vertexId != 0 ) { // If we were adding at the end of the feature, we need to update the index - mMouseAtEndpoint.reset( new Vertex( mMouseAtEndpoint->layer, mMouseAtEndpoint->fid, mMouseAtEndpoint->vertexId + 1 ) ); + mMouseAtEndpoint = std::make_unique< Vertex >( mMouseAtEndpoint->layer, mMouseAtEndpoint->fid, mMouseAtEndpoint->vertexId + 1 ); } // And then we just restart the drag startDraggingAddVertexAtEndpoint( mapPoint ); @@ -3079,7 +3079,7 @@ void QgsVertexTool::rangeMethodReleaseEvent( QgsMapMouseEvent *e ) QgsPointLocator::Match m = snapToEditableLayer( e ); if ( m.hasVertex() ) { - mRangeSelectionFirstVertex.reset( new Vertex( m.layer(), m.featureId(), m.vertexIndex() ) ); + mRangeSelectionFirstVertex = std::make_unique< Vertex >( m.layer(), m.featureId(), m.vertexIndex() ); setHighlightedVertices( QList() << *mRangeSelectionFirstVertex ); } } From 882b0c9a1cc34ebe83fa6f320001b33aa879f3dd Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 3 Sep 2025 11:40:34 +1000 Subject: [PATCH 09/10] Add additional tests (cherry picked from commit b7123e38c77a4751bde8ae93a2e0ba6009d3dc98) --- src/app/vertextool/qgsvertextool.h | 2 ++ tests/src/app/testqgsvertextool.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app/vertextool/qgsvertextool.h b/src/app/vertextool/qgsvertextool.h index e87998729a8..ac7b9517e39 100644 --- a/src/app/vertextool/qgsvertextool.h +++ b/src/app/vertextool/qgsvertextool.h @@ -510,6 +510,8 @@ class APP_EXPORT QgsVertexTool : public QgsMapToolAdvancedDigitizing std::unique_ptr mRangeSelectionFirstVertex; VertexToolMode mMode = AllLayers; + + friend class TestQgsVertexTool; }; diff --git a/tests/src/app/testqgsvertextool.cpp b/tests/src/app/testqgsvertextool.cpp index cbdde67c006..c73affa6dce 100644 --- a/tests/src/app/testqgsvertextool.cpp +++ b/tests/src/app/testqgsvertextool.cpp @@ -548,12 +548,17 @@ void TestQgsVertexTool::testMoveVertex() // move vertex of linestring mouseClick( 2, 1, Qt::LeftButton ); + QCOMPARE( mVertexTool->mDraggingVertexType, QgsVertexTool::DraggingVertexType::MovingVertex ); + QCOMPARE( mVertexTool->mDraggingVertex->layer->id(), mLayerLine->id() ); + QCOMPARE( mVertexTool->mDraggingVertex->fid, mFidLineF1 ); + QCOMPARE( mVertexTool->mDraggingVertex->vertexId, 0 ); mouseClick( 2, 2, Qt::LeftButton ); + QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry().asWkt( 0 ), "LineString (2 2, 1 1, 1 3)" ); + QCOMPARE( mLayerLine->undoStack()->count(), 2 ); QCOMPARE( mLayerLine->undoStack()->index(), 2 ); - QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 2, 1 1, 1 3)" ) ); mLayerLine->undoStack()->undo(); QCOMPARE( mLayerLine->undoStack()->index(), 1 ); From bfa7326e55e2e9a05e1e60f30ca8ad17372ac72c Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 3 Sep 2025 11:41:17 +1000 Subject: [PATCH 10/10] Fix fragility in vertex tool test We have two layers with overlapping line features -- one is reprojected and the other isn't. The majority of tests are only using the non-reprojected layer, but were setup in such a way that the vertex tool edits MAY snap to the features from the reprojected line layer and edit that layer instead. Fix this by only making the reprojected layer editable for the test which it's needed for, so that the other tests ALWAYS modify the non-reprojected layer. (cherry picked from commit 11497cf2eb3bf6bdd371095651698472a8924f46) --- tests/src/app/testqgsvertextool.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/src/app/testqgsvertextool.cpp b/tests/src/app/testqgsvertextool.cpp index c73affa6dce..1f17dcb2315 100644 --- a/tests/src/app/testqgsvertextool.cpp +++ b/tests/src/app/testqgsvertextool.cpp @@ -219,7 +219,7 @@ void TestQgsVertexTool::init() mLayerMultiLine = new QgsVectorLayer( QStringLiteral( "MultiLineString?" ), QStringLiteral( "layer multiline" ), QStringLiteral( "memory" ) ); mLayerMultiLine->setCrs( mFake27700 ); QVERIFY( mLayerMultiLine->isValid() ); - mLayerLineReprojected = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:3857" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) ); + mLayerLineReprojected = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:3857" ), QStringLiteral( "layer line reprojected" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerLineReprojected->isValid() ); mLayerPolygon = new QgsVectorLayer( QStringLiteral( "Polygon?" ), QStringLiteral( "layer polygon" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerPolygon->isValid() ); @@ -233,7 +233,7 @@ void TestQgsVertexTool::init() mLayerPointZ = new QgsVectorLayer( QStringLiteral( "PointZ?" ), QStringLiteral( "layer pointz" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerPointZ->isValid() ); mLayerPointZ->setCrs( mFake27700 ); - mLayerLineZ = new QgsVectorLayer( QStringLiteral( "LineStringZ?" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) ); + mLayerLineZ = new QgsVectorLayer( QStringLiteral( "LineStringZ?" ), QStringLiteral( "layer line z" ), QStringLiteral( "memory" ) ); QVERIFY( mLayerLineZ->isValid() ); mLayerLineZ->setCrs( mFake27700 ); mLayerCompoundCurve = new QgsVectorLayer( QStringLiteral( "CompoundCurve?" ), QStringLiteral( "layer compound curve" ), QStringLiteral( "memory" ) ); @@ -288,7 +288,8 @@ void TestQgsVertexTool::init() mLayerLineReprojected->startEditing(); mLayerLineReprojected->addFeature( lineF13857 ); - mFidLineF13857 = lineF13857.id(); + mLayerLineReprojected->commitChanges(); + mFidLineF13857 = *( mLayerLineReprojected->allFeatureIds().begin() ); QCOMPARE( mLayerLineReprojected->featureCount(), ( long ) 1 ); mLayerPolygon->startEditing(); @@ -1014,6 +1015,9 @@ void TestQgsVertexTool::testConvertVertex() void TestQgsVertexTool::testMoveMultipleVertices() { + mLayerLineReprojected->startEditing(); + QCOMPARE( mLayerLineReprojected->undoStack()->index(), 0 ); + QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (2 1, 1 1, 1 3)" ) ); QCOMPARE( mLayerLineReprojected->getFeature( mFidLineF13857 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (-228837 6428900, -228838 6428900, -228838 6428903)" ) ); @@ -1035,7 +1039,7 @@ void TestQgsVertexTool::testMoveMultipleVertices() mLayerLine->undoStack()->undo(); QCOMPARE( mLayerLine->undoStack()->index(), 1 ); - QCOMPARE( mLayerLineReprojected->undoStack()->index(), 2 ); + QCOMPARE( mLayerLineReprojected->undoStack()->index(), 1 ); QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (2 1, 1 1, 1 3)" ) ); QCOMPARE( mLayerLineReprojected->getFeature( mFidLineF13857 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (-228837 6428900, -228840 6428899, -228840 6428902)" ) );