// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.command; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.openstreetmap.josm.command.CommandTest.CommandTestDataWithRelation; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Relation; import org.openstreetmap.josm.data.osm.User; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.osm.WaySegment; import org.openstreetmap.josm.gui.layer.OsmDataLayer; import org.openstreetmap.josm.testutils.JOSMTestRules; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; /** * Unit tests of {@link DeleteCommand} class. */ public class DeleteCommandTest { /** * We need prefs for nodes. */ @Rule @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules().preferences().i18n(); private CommandTestDataWithRelation testData; /** * Set up the test data. */ @Before public void createTestData() { testData = new CommandTestDataWithRelation(); } /** * A simple deletion test with no references */ @Test public void testSimpleDelete() { Node node = testData.createNode(15); assertTrue(testData.layer.data.allPrimitives().contains(node)); new DeleteCommand(node).executeCommand(); assertTrue(node.isDeleted()); assertTrue(node.isModified()); assertFalse(testData.layer.data.allNonDeletedPrimitives().contains(node)); } /** * A delete should not delete referred objects but should should remove the reference. */ @Test public void testDeleteIgnoresReferences() { assertTrue(testData.existingNode.getReferrers().contains(testData.existingRelation)); new DeleteCommand(testData.existingRelation).executeCommand(); assertTrue(testData.existingRelation.isDeleted()); assertEquals(0, testData.existingRelation.getMembersCount()); assertFalse(testData.existingNode.isDeleted()); assertFalse(testData.existingWay.isDeleted()); assertFalse(testData.existingNode.getReferrers().contains(testData.existingRelation)); // same for the way assertTrue(testData.existingNode.getReferrers().contains(testData.existingWay)); new DeleteCommand(testData.existingWay).executeCommand(); assertEquals(0, testData.existingWay.getNodesCount()); assertFalse(testData.existingNode.getReferrers().contains(testData.existingWay)); } /** * A delete should delete all objects with references to the deleted one */ @Test(expected = IllegalArgumentException.class) public void testDeleteFailsOnDelted() { new DeleteCommand(testData.existingRelation).executeCommand(); new DeleteCommand(testData.existingRelation).executeCommand(); } /** * A delete should delete all objects with references to the deleted one */ @Test public void testReferredDelete() { DeleteCommand.deleteWithReferences(testData.layer, Arrays.asList(testData.existingNode), true).executeCommand(); assertTrue(testData.existingNode.isDeleted()); assertEquals(0, testData.existingWay.getNodesCount()); assertTrue(testData.existingWay.isDeleted()); } /** * Delete nodes that would be without reference afterwards. */ @Test public void testDelteNodesInWay() { testData.existingNode.removeAll(); // That untagged node should be deleted. testData.existingNode2.removeAll(); DeleteCommand.delete(testData.layer, Arrays.asList(testData.existingWay), true, true).executeCommand(); assertTrue(testData.existingWay.isDeleted()); assertTrue(testData.existingNode2.isDeleted()); assertFalse(testData.existingNode.isDeleted()); assertFalse(testData.existingRelation.isDeleted()); // Same test, now with tagged nodes Node node1 = testData.createNode(15); Node node2 = testData.createNode(16); Node node3 = testData.createNode(17); Node node4 = testData.createNode(18); node2.removeAll(); node4.removeAll(); Way way1 = new Way(25, 1); way1.setNodes(Arrays.asList(node1, node2, node3)); testData.layer.data.addPrimitive(way1); Way way2 = new Way(26, 1); way2.setNodes(Arrays.asList(node2, node3, node4)); testData.layer.data.addPrimitive(way2); DeleteCommand.delete(testData.layer, Arrays.asList(way1, way2), true, true).executeCommand(); assertTrue(way1.isDeleted()); assertTrue(way2.isDeleted()); assertFalse(node1.isDeleted()); assertTrue(node2.isDeleted()); assertFalse(node3.isDeleted()); assertTrue(node4.isDeleted()); } /** * Test that {@link DeleteCommand} checks for non-null. */ @Test(expected = IllegalArgumentException.class) public void testConsistency() { new DeleteCommand(Arrays.asList(testData.existingNode, testData.existingWay, null)); } /** * Test that {@link DeleteCommand} checks for the dataset */ @Test(expected = IllegalArgumentException.class) public void testConsistencyDataset() { testData.layer.data.removePrimitive(testData.existingNode); new DeleteCommand(Arrays.asList(testData.existingNode, testData.existingWay)); } /** * Test that {@link DeleteCommand} checks for non-empty list */ @Test(expected = IllegalArgumentException.class) public void testConsistencyNonEmpty() { new DeleteCommand(Arrays.<OsmPrimitive>asList()); } /** * Test that {@link DeleteCommand} checks for non-null list */ @Test(expected = IllegalArgumentException.class) public void testConsistencyNonNull() { new DeleteCommand((Collection<OsmPrimitive>) null); } /** * Test {@link DeleteCommand#undoCommand()} */ @Test public void testUndo() { DeleteCommand command = new DeleteCommand( Arrays.asList(testData.existingNode, testData.existingNode2, testData.existingWay)); command.executeCommand(); assertTrue(testData.existingNode.isDeleted()); assertTrue(testData.existingWay.isDeleted()); command.undoCommand(); assertFalse(testData.existingNode.isDeleted()); assertFalse(testData.existingWay.isDeleted()); assertEquals("existing", testData.existingNode.get("existing")); command.executeCommand(); assertTrue(testData.existingNode.isDeleted()); assertTrue(testData.existingWay.isDeleted()); } /** * Test {@link DeleteCommand#deleteWaySegment(OsmDataLayer, org.openstreetmap.josm.data.osm.WaySegment)} * Way with only 1 segment */ @Test public void testDeleteWaySegment() { Way way1 = testData.createWay(100, testData.createNode(101), testData.createNode(102)); WaySegment ws = new WaySegment(way1, 0); Command command = DeleteCommand.deleteWaySegment(testData.layer, ws); command.executeCommand(); assertTrue(way1.isDeleted()); } /** * Test {@link DeleteCommand#deleteWaySegment(OsmDataLayer, org.openstreetmap.josm.data.osm.WaySegment)} * Delete end of way */ @Test public void testDeleteWaySegmentEndOfWay() { Way way = testData.createWay(200, testData.createNode(201), testData.createNode(202), testData.createNode(203), testData.createNode(204)); WaySegment ws = new WaySegment(way, 2); Command command = DeleteCommand.deleteWaySegment(testData.layer, ws); command.executeCommand(); assertEquals(3, way.getNodesCount()); assertEquals(201, way.getNodeId(0)); assertEquals(202, way.getNodeId(1)); assertEquals(203, way.getNodeId(2)); } /** * Test {@link DeleteCommand#deleteWaySegment(OsmDataLayer, org.openstreetmap.josm.data.osm.WaySegment)} * Delete start of way */ @Test public void testDeleteWaySegmentStartOfWay() { Way way = testData.createWay(100, testData.createNode(101), testData.createNode(102), testData.createNode(103), testData.createNode(104)); WaySegment ws = new WaySegment(way, 0); Command command = DeleteCommand.deleteWaySegment(testData.layer, ws); command.executeCommand(); assertEquals(3, way.getNodesCount()); assertEquals(102, way.getNodeId(0)); assertEquals(103, way.getNodeId(1)); assertEquals(104, way.getNodeId(2)); } /** * Test {@link DeleteCommand#deleteWaySegment(OsmDataLayer, org.openstreetmap.josm.data.osm.WaySegment)} * Delete start of way */ @Test public void testDeleteWaySegmentSplit() { Node node103 = testData.createNode(103); Node node104 = testData.createNode(104); Way way = testData.createWay(100, testData.createNode(101), testData.createNode(102), node103, node104); WaySegment ws = new WaySegment(way, 1); Command command = DeleteCommand.deleteWaySegment(testData.layer, ws); command.executeCommand(); assertEquals(2, way.getNodesCount()); assertEquals(101, way.getNodeId(0)); assertEquals(102, way.getNodeId(1)); // there needs to be a new way assertEquals(1, node104.getReferrers().size()); Way newWay = (Way) node104.getReferrers().get(0); assertEquals(2, newWay.getNodesCount()); assertEquals(103, newWay.getNodeId(0)); assertEquals(104, newWay.getNodeId(1)); } /** * Test {@link DeleteCommand#deleteWaySegment(OsmDataLayer, org.openstreetmap.josm.data.osm.WaySegment)} * Delete start of way */ @Test public void testDeleteWaySegmentCycle() { Node n = testData.createNode(101); Way way = testData.createWay(100, n, testData.createNode(102), testData.createNode(103), testData.createNode(104), n); WaySegment ws = new WaySegment(way, 2); Command command = DeleteCommand.deleteWaySegment(testData.layer, ws); command.executeCommand(); assertEquals(4, way.getNodesCount()); assertEquals(104, way.getNodeId(0)); assertEquals(101, way.getNodeId(1)); assertEquals(102, way.getNodeId(2)); assertEquals(103, way.getNodeId(3)); } /** * Tests {@link DeleteCommand#getChildren()} */ @Test public void testGetChildren() { testData.existingNode.put("name", "xy"); Collection<PseudoCommand> children = new DeleteCommand(Arrays.<OsmPrimitive>asList(testData.existingNode, testData.existingNode2)) .getChildren(); assertEquals(2, children.size()); assertTrue(children.stream().allMatch(c -> c.getParticipatingPrimitives().size() == 1)); assertTrue(children.stream().anyMatch(c -> c.getParticipatingPrimitives().iterator().next() == testData.existingNode)); assertTrue(children.stream().anyMatch(c -> c.getParticipatingPrimitives().iterator().next() == testData.existingNode2)); assertTrue(children.stream().anyMatch(c -> c.getDescriptionText().matches("Deleted '.*xy.*'"))); } /** * Tests {@link DeleteCommand#fillModifiedData(java.util.Collection, java.util.Collection, java.util.Collection)} */ @Test public void testFillModifiedData() { ArrayList<OsmPrimitive> modified = new ArrayList<>(); ArrayList<OsmPrimitive> deleted = new ArrayList<>(); ArrayList<OsmPrimitive> added = new ArrayList<>(); new DeleteCommand(Arrays.<OsmPrimitive>asList(testData.existingNode)).fillModifiedData(modified, deleted, added); // intentionally left empty. assertArrayEquals(new Object[] {}, modified.toArray()); assertArrayEquals(new Object[] {}, deleted.toArray()); assertArrayEquals(new Object[] {}, added.toArray()); } /** * Tests {@link DeleteCommand#getParticipatingPrimitives()} */ @Test public void testGetParticipatingPrimitives() { DeleteCommand command = new DeleteCommand(Arrays.<OsmPrimitive>asList(testData.existingNode)); assertArrayEquals(new Object[] {testData.existingNode }, command.getParticipatingPrimitives().toArray()); DeleteCommand command2 = new DeleteCommand( Arrays.<OsmPrimitive>asList(testData.existingNode, testData.existingWay)); assertArrayEquals(new Object[] {testData.existingNode, testData.existingWay}, command2.getParticipatingPrimitives().toArray()); } /** * Test {@link DeleteCommand#getDescriptionText()} */ @Test public void testDescription() { Node node = testData.createNode(100); node.put("name", "xy"); Way way = testData.createWay(101); way.put("name", "xy"); Relation relation = testData.createRelation(102); relation.put("name", "xy"); List<OsmPrimitive> nodeList = Arrays.<OsmPrimitive>asList(node); assertTrue(new DeleteCommand(nodeList).getDescriptionText().matches("Delete node .*xy.*")); List<OsmPrimitive> wayList = Arrays.<OsmPrimitive>asList(way); assertTrue(new DeleteCommand(wayList).getDescriptionText().matches("Delete way .*xy.*")); List<OsmPrimitive> relationList = Arrays.<OsmPrimitive>asList(relation); assertTrue(new DeleteCommand(relationList).getDescriptionText().matches("Delete relation .*xy.*")); List<OsmPrimitive> nodesList = Arrays.<OsmPrimitive>asList(node, testData.createNode(110)); assertTrue(new DeleteCommand(nodesList).getDescriptionText().matches("Delete 2 nodes")); List<OsmPrimitive> waysList = Arrays.<OsmPrimitive>asList(way, testData.createWay(111)); assertTrue(new DeleteCommand(waysList).getDescriptionText().matches("Delete 2 ways")); List<OsmPrimitive> relationsList = Arrays.<OsmPrimitive>asList(relation, testData.createRelation(112)); assertTrue(new DeleteCommand(relationsList).getDescriptionText().matches("Delete 2 relations")); List<OsmPrimitive> mixed = Arrays.<OsmPrimitive>asList(node, way, relation); assertTrue(new DeleteCommand(mixed).getDescriptionText().matches("Delete 3 objects")); } /** * Unit test of methods {@link DeleteCommand#equals} and {@link DeleteCommand#hashCode}. */ @Test public void testEqualsContract() { EqualsVerifier.forClass(DeleteCommand.class).usingGetClass() .withPrefabValues(DataSet.class, new DataSet(), new DataSet()) .withPrefabValues(User.class, User.createOsmUser(1, "foo"), User.createOsmUser(2, "bar")) .withPrefabValues(OsmDataLayer.class, new OsmDataLayer(new DataSet(), "1", null), new OsmDataLayer(new DataSet(), "2", null)) .suppress(Warning.NONFINAL_FIELDS) .verify(); } }