-
-
Notifications
You must be signed in to change notification settings - Fork 338
Added qml tests for the vertex editor geometry tool #7579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
kaustuvpokharel
wants to merge
5
commits into
master
Choose a base branch
from
vertex-pr
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+335
−0
Open
Changes from 1 commit
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
f0d5c79
qml tests for the vertex editor geometry tool
kaustuvpokharel 1de558b
improveing vertex editor move/remove tests to assert exact outcomes
kaustuvpokharel cd33207
pin map extent in vertex tests so vertex moves clear the pixel in ci
kaustuvpokharel 884a251
debug points
kaustuvpokharel e08efc1
test vertex editor move on the vertex model geometry to avoid layer c…
kaustuvpokharel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,265 @@ | ||
| import QtQuick | ||
| import QtTest | ||
| import org.qfield | ||
| import org.qgis | ||
| import Theme | ||
| import "../../src/qml/geometryeditors" as GeometryEditors | ||
|
|
||
| // tests for the vertex editor tool. The vertex model itself is tested in | ||
| // test_vertexmodel.cpp, so here we only check the tool around it: init wiring, | ||
| // applyChanges and the autoSave branch, cancel, remove, and undo. | ||
| // | ||
| // canvasClicked is not tested here on purpose. It turns a screen point into a | ||
| // map coordinate through mapSettings.screenToCoordinate, which only makes sense | ||
| // with a real rendered canvas. without one the screen-to-map math is meaningless, | ||
| // so a click test would just be asserting made up numbers, so that path belongs in | ||
| // an integration (spix) test, not here. | ||
| // | ||
| // the tool reads a few things from its parent scope in the app, so we provide | ||
| // them here as plain items the same way tst_featureForm.qml does. | ||
| TestCase { | ||
| id: testCase | ||
| name: "GeometryEditorVertex" | ||
|
|
||
| property var fieldsLayer: qgisProject.mapLayersByName("Fields")[0] | ||
| property var tracksLayer: qgisProject.mapLayersByName("Tracks")[0] | ||
|
|
||
| // we never commit to the layer, so just make sure any open edit session is | ||
| // rolled back between tests and the layer is left clean | ||
| function cleanup() { | ||
| vertexEditor.cancel(); | ||
| if (fieldsLayer.editBuffer()) { | ||
| fieldsLayer.rollBack(); | ||
| } | ||
| if (tracksLayer.editBuffer()) { | ||
| tracksLayer.rollBack(); | ||
| } | ||
| qfieldSettings.autoSave = false; | ||
| } | ||
|
|
||
| function makeFeatureModel(layer, fid) { | ||
| featureModel.currentLayer = layer; | ||
| featureModel.feature = layer.getFeature(fid); | ||
| featureModel.applyGeometryToVertexModel(); | ||
| return featureModel; | ||
| } | ||
|
|
||
| // Fields/39 is a simple polygon. its vertex model interleaves segment | ||
| // candidates with real vertices, so the real (existing) vertices sit at the | ||
| // odd indices and 1 is the first of them. | ||
| function makeFieldsModel() { | ||
| return makeFeatureModel(fieldsLayer, "39"); | ||
| } | ||
|
|
||
| // select the first real vertex and move it, so the model goes dirty like it | ||
| // would after a drag on the canvas. the layer is in meters so a meter-scale | ||
| // move is well above the tools ignore-tiny-moves threshold. | ||
| function selectAndMoveFirstVertex() { | ||
| const vertexModel = featureModel.vertexModel; | ||
| vertexModel.editingMode = VertexModel.EditVertex; | ||
| vertexModel.currentVertexIndex = 1; | ||
| const point = vertexModel.currentPoint; | ||
| vertexModel.currentPoint = GeometryUtils.point(point.x + 5, point.y + 5); | ||
| } | ||
|
|
||
| MapSettings { | ||
| id: mapSettingsItem | ||
| destinationCrs: CoordinateReferenceSystemUtils.fromDescription("EPSG:3857") | ||
| } | ||
|
|
||
| FeatureModel { | ||
| id: featureModel | ||
| project: qgisProject | ||
|
|
||
| vertexModel: VertexModel { | ||
| id: geometryEditingVertexModel | ||
| } | ||
| } | ||
|
|
||
| GeometryEditors.VertexEditor { | ||
| id: vertexEditor | ||
| featureModel: featureModel | ||
| mapSettings: mapSettingsItem | ||
| } | ||
|
|
||
| function test_initWiresFeatureModelAndResetsCurrentVertex() { | ||
| const model = makeFieldsModel(); | ||
| model.vertexModel.currentVertexIndex = 3; | ||
|
|
||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
|
|
||
| compare(vertexEditor.featureModel, model); | ||
| // init should always start with no vertex selected | ||
| compare(model.vertexModel.currentVertexIndex, -1); | ||
| } | ||
|
|
||
| function test_blockingFollowsVertexModelDirtyState() { | ||
| const model = makeFieldsModel(); | ||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
| compare(vertexEditor.blocking, false); | ||
|
|
||
| selectAndMoveFirstVertex(); | ||
|
|
||
| // blocking is just dirty, so an unsaved edit should block | ||
| compare(model.vertexModel.dirty, true); | ||
| compare(vertexEditor.blocking, true); | ||
| } | ||
|
|
||
| function test_applyChangesAppliesMovedVertexToLayerBuffer() { | ||
| const model = makeFieldsModel(); | ||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
|
|
||
| selectAndMoveFirstVertex(); | ||
| const before = model.feature.geometry.asWkt(); | ||
|
|
||
| // apply pushes the vertex model edit onto the feature. we check the feature | ||
| // geometry changed but never commit, so the layer file is untouched | ||
| vertexEditor.applyChanges(true); | ||
|
|
||
| verify(model.feature.geometry.asWkt() !== before); | ||
| } | ||
|
|
||
| function test_applyChangesWithAutoSaveOffDoesNotApply() { | ||
| qfieldSettings.autoSave = false; | ||
| const model = makeFieldsModel(); | ||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
|
|
||
| selectAndMoveFirstVertex(); | ||
| const before = model.feature.geometry.asWkt(); | ||
|
|
||
| // the next/prev/add buttons call applyChanges(autoSave). with autoSave off | ||
| // the edit stays in the model and is not pushed to the feature yet | ||
| vertexEditor.applyChanges(qfieldSettings.autoSave); | ||
|
|
||
| compare(model.feature.geometry.asWkt(), before); | ||
| compare(model.vertexModel.dirty, true); | ||
| } | ||
|
|
||
| function test_applyChangesNoOpWhenNotDirty() { | ||
| const model = makeFieldsModel(); | ||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
| compare(model.vertexModel.dirty, false); | ||
|
|
||
| const before = model.feature.geometry.asWkt(); | ||
|
|
||
| // nothing changed, so apply should do nothing | ||
| vertexEditor.applyChanges(true); | ||
|
|
||
| compare(model.feature.geometry.asWkt(), before); | ||
| } | ||
|
|
||
| function test_cancelResetsEditingModeAndClearsDirty() { | ||
| const model = makeFieldsModel(); | ||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
| selectAndMoveFirstVertex(); | ||
| compare(model.vertexModel.dirty, true); | ||
|
|
||
| vertexEditor.cancel(); | ||
|
|
||
| // cancel throws away the edit and leaves editing mode | ||
| compare(model.vertexModel.editingMode, VertexModel.NoEditing); | ||
| compare(model.vertexModel.dirty, false); | ||
| } | ||
|
|
||
| function test_removeVertexReducesCountAndSetsDirty() { | ||
| const model = makeFieldsModel(); | ||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
| const vertexModel = model.vertexModel; | ||
|
|
||
| vertexModel.editingMode = VertexModel.EditVertex; | ||
| vertexModel.currentVertexIndex = 1; | ||
| // the polygon has 12 real vertices, well above the minimum, so removing one is allowed | ||
| verify(vertexModel.canRemoveVertex); | ||
| const countBefore = vertexModel.vertexCount; | ||
|
|
||
| vertexModel.removeCurrentVertex(); | ||
|
|
||
| // removing a vertex drops the row count and marks the edit dirty | ||
| verify(vertexModel.vertexCount < countBefore); | ||
|
kaustuvpokharel marked this conversation as resolved.
Outdated
|
||
| compare(vertexModel.dirty, true); | ||
| } | ||
|
|
||
| function test_canRemoveVertexFalseWithoutEditMode() { | ||
| const model = makeFieldsModel(); | ||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
|
|
||
| // canRemoveVertex only holds while a vertex is being edited, never before | ||
| compare(model.vertexModel.editingMode, VertexModel.NoEditing); | ||
| compare(model.vertexModel.canRemoveVertex, false); | ||
| } | ||
|
|
||
| function test_undoRestoresGeometryAfterMove() { | ||
| const model = makeFieldsModel(); | ||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
| const vertexModel = model.vertexModel; | ||
|
|
||
| const before = vertexModel.currentPoint; | ||
| selectAndMoveFirstVertex(); | ||
| verify(vertexModel.canUndo); | ||
|
|
||
| vertexModel.undoHistory(); | ||
|
|
||
| // undo should put the moved vertex back where it started | ||
| vertexModel.currentVertexIndex = 1; | ||
| const restored = vertexModel.currentPoint; | ||
| compare(restored.x, before.x); | ||
| compare(restored.y, before.y); | ||
| } | ||
|
|
||
| function test_undoIsNoOpWithEmptyHistory() { | ||
| const model = makeFieldsModel(); | ||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
|
|
||
| // nothing has been edited, so there is nothing to undo | ||
| compare(model.vertexModel.canUndo, false); | ||
| model.vertexModel.undoHistory(); | ||
| compare(model.vertexModel.dirty, false); | ||
| } | ||
|
|
||
| function test_applyChangesAppliesMovedVertexOnLineLayer() { | ||
| // same apply path but on a line feature, to cover the line geometry branch | ||
| const model = makeFeatureModel(tracksLayer, "1"); | ||
| vertexEditor.init(model, mapSettingsItem, null, null); | ||
| const vertexModel = model.vertexModel; | ||
|
|
||
| // on a line the first real vertex is also at an odd index | ||
| vertexModel.editingMode = VertexModel.EditVertex; | ||
| vertexModel.currentVertexIndex = 1; | ||
| const point = vertexModel.currentPoint; | ||
| vertexModel.currentPoint = GeometryUtils.point(point.x + 5, point.y + 5); | ||
| compare(vertexModel.dirty, true); | ||
|
|
||
| const before = model.feature.geometry.asWkt(); | ||
| vertexEditor.applyChanges(true); | ||
|
|
||
| verify(model.feature.geometry.asWkt() !== before); | ||
|
kaustuvpokharel marked this conversation as resolved.
Outdated
|
||
| } | ||
|
kaustuvpokharel marked this conversation as resolved.
|
||
|
|
||
| // scope objects the tool expects from the app | ||
| Item { | ||
| id: mainWindowItem | ||
| } | ||
|
|
||
| Item { | ||
| id: qfieldSettings | ||
| property bool autoSave: false | ||
| } | ||
|
|
||
| Item { | ||
| id: coordinateLocator | ||
| property var currentCoordinate: GeometryUtils.point(0, 0) | ||
| property string positionInformation: "" | ||
| property string topSnappingResult: "" | ||
| property bool positionLocked: false | ||
| } | ||
|
|
||
| Item { | ||
| id: projectInfo | ||
| property string cloudUserInformation: "" | ||
| } | ||
|
|
||
| Item { | ||
| id: positionSource | ||
| property string positionInformation: "" | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.