// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.actions;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openstreetmap.josm.JOSMFixture;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.actions.AlignInLineAction.InvalidSelection;
import org.openstreetmap.josm.actions.AlignInLineAction.Line;
import org.openstreetmap.josm.data.coor.EastNorth;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.Way;
import org.openstreetmap.josm.gui.layer.OsmDataLayer;
/**
* Unit tests for class {@link AlignInLineAction}.
*/
public final class AlignInLineActionTest {
/** Class under test. */
private static AlignInLineAction action;
/**
* Setup test.
*/
@BeforeClass
public static void setUp() {
JOSMFixture.createUnitTestFixture().init(true);
// Enable "Align in line" feature.
action = Main.main.menu.alignInLine;
action.setEnabled(true);
}
/**
* Test case: only nodes selected, part of an open way: align these nodes on the line passing through the extremity
* nodes (the most distant in the way sequence, not the most euclidean-distant). See
* https://josm.openstreetmap.de/ticket/9605#comment:3. Note that in this test, after alignment, way is overlapping
* itself.
*/
@Test
public void testNodesOpenWay() {
DataSet dataSet = new DataSet();
OsmDataLayer layer = new OsmDataLayer(dataSet, OsmDataLayer.createNewName(), null);
// Create test points, lower left is (0,0).
//
// 1 - - -
// - 3 - 2
// - - - -
Node point1 = new Node(new EastNorth(0, 2));
Node point2 = new Node(new EastNorth(3, 1));
Node point3 = new Node(new EastNorth(1, 1));
try {
Main.getLayerManager().addLayer(layer);
// Create an open way.
createWay(dataSet, point1, point2, point3);
// Select nodes to align.
dataSet.addSelected(point1, point2, point3);
action.actionPerformed(null);
} finally {
// Ensure we clean the place before leaving, even if test fails.
Main.getLayerManager().removeLayer(layer);
}
// Points 1 and 3 are the extremities and must not have moved. Only point 2 must have moved.
assertCoordEq(point1, 0, 2);
assertCoordEq(point2, 2, 0);
assertCoordEq(point3, 1, 1);
}
/**
* Test case: only nodes selected, part of a closed way: align these nodes on the line passing through the most
* distant nodes.
*/
@Test
public void testNodesClosedWay() {
DataSet dataSet = new DataSet();
OsmDataLayer layer = new OsmDataLayer(dataSet, OsmDataLayer.createNewName(), null);
// Create test points, lower left is (0,0).
//
// 4 - 3
// - - -
// 1 - 2
Node point1 = new Node(new EastNorth(0, 0));
Node point2 = new Node(new EastNorth(2, 0));
Node point3 = new Node(new EastNorth(2, 2));
Node point4 = new Node(new EastNorth(0, 2));
try {
Main.getLayerManager().addLayer(layer);
// Create a closed way.
createWay(dataSet, point1, point2, point3, point4, point1);
// Select nodes to align (point1 must be in the second position to exhibit the bug).
dataSet.addSelected(point4, point1, point2);
action.actionPerformed(null);
} finally {
// Ensure we clean the place before leaving, even if test fails.
Main.getLayerManager().removeLayer(layer);
}
// Only point 1 must have moved.
assertCoordEq(point1, 1, 1);
assertCoordEq(point2, 2, 0);
assertCoordEq(point3, 2, 2);
assertCoordEq(point4, 0, 2);
}
/**
* Test case: only nodes selected, part of multiple ways: align these nodes on the line passing through the most
* distant nodes.
*/
@Test
public void testNodesOpenWays() {
DataSet dataSet = new DataSet();
OsmDataLayer layer = new OsmDataLayer(dataSet, OsmDataLayer.createNewName(), null);
// Create test points, lower left is (0,0).
//
// 1 - -
// 3 - 2
// - - 4
Node point1 = new Node(new EastNorth(0, 2));
Node point2 = new Node(new EastNorth(2, 1));
Node point3 = new Node(new EastNorth(0, 1));
Node point4 = new Node(new EastNorth(2, 0));
try {
Main.getLayerManager().addLayer(layer);
// Create 2 ways.
createWay(dataSet, point1, point2);
createWay(dataSet, point3, point4);
// Select nodes to align.
dataSet.addSelected(point1, point2, point3, point4);
// Points must align between points 1 and 4.
action.actionPerformed(null);
} finally {
// Ensure we clean the place before leaving, even if test fails.
Main.getLayerManager().removeLayer(layer);
}
assertCoordEq(point1, 0, 2);
assertCoordEq(point2, 1.5, 0.5);
assertCoordEq(point3, 0.5, 1.5);
assertCoordEq(point4, 2, 0);
}
/**
* Create a way made of the provided nodes and select nodes.
*
* @param dataSet Dataset in which adding nodes.
* @param nodes List of nodes to add to dataset.
*/
private void createWay(DataSet dataSet, Node... nodes) {
Way way = new Way();
dataSet.addPrimitive(way);
for (Node node : nodes) {
// Add primitive to dataset only if not already included.
if (dataSet.getPrimitiveById(node) == null)
dataSet.addPrimitive(node);
way.addNode(node);
}
}
/**
* Assert that the provided node has the specified coordinates. If not fail the test.
*
* @param node Node to test.
* @param x X coordinate.
* @param y Y coordinate.
*/
private void assertCoordEq(Node node, double x, double y) {
EastNorth coordinate = node.getEastNorth();
assertEquals("Wrong x coordinate.", x, coordinate.getX(), LatLon.MAX_SERVER_PRECISION);
assertEquals("Wrong y coordinate.", y, coordinate.getY(), LatLon.MAX_SERVER_PRECISION);
}
/**
* Test that a {@link Line} can be constructed with nodes of different coordinates.
* @throws InvalidSelection never
*/
@Test
public void testLineDifferentCoordinates() throws InvalidSelection {
assertNotNull(new Line(new Node(new EastNorth(0, 1)),
new Node(new EastNorth(0, 2))));
assertNotNull(new Line(new Node(new EastNorth(0, 1)),
new Node(new EastNorth(1, 1))));
assertNotNull(new Line(new Node(new EastNorth(0, 1)),
new Node(new EastNorth(0+1e-150, 1+1e-150))));
}
/**
* Test that a {@link Line} cannot be constructed with nodes of same coordinates.
* @throws InvalidSelection always
*/
@Test(expected = InvalidSelection.class)
public void testLineSameCoordinates1() throws InvalidSelection {
new Line(new Node(new EastNorth(0, 1)),
new Node(new EastNorth(0, 1)));
}
/**
* Test that a {@link Line} cannot be constructed with nodes of same coordinates.
* @throws InvalidSelection always
*/
@Test(expected = InvalidSelection.class)
public void testLineSameCoordinates2() throws InvalidSelection {
new Line(new Node(new EastNorth(0, 1)),
new Node(new EastNorth(0+1e-175, 1+1e-175)));
}
}