source: josm/trunk/test/unit/org/openstreetmap/josm/actions/CombineWayActionTest.java@ 15574

Last change on this file since 15574 was 15574, checked in by GerdP, 4 years ago

fix #18367 and #18385: CombineWayAction (C) refuses to combine ways or silently reverses ways
Changes:

  • try first to combine the ways with the method Multipolygon.joinWays() If that method returns a single line string we can use it, else use the result of NodeGraph.buildSpanningPathNoRemove(). Both methods will not add or remove segments
  • if ways are combined execute checks for overlapping segments or self-intersection and show a notification popup right after the command was added to the UndoRedoHandler
  • The code which handles reversed ways needed changes. In the unpatched version it sometimes claims wrongly that ways were reversed, in special cases it sometimes silently reverted ways. The old code did not handle the case properly that a node can appear more than once. I really hope that I got it right now.
  • Fix some sonarlint issues
  • let NodeGraph routines return an ArrayList instead of a LinkedList (improves performance a bit)
  • Add unit tests
  • Property svn:eol-style set to native
File size: 7.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.junit.Assert.assertEquals;
5import static org.junit.Assert.assertFalse;
6
7import java.io.IOException;
8import java.io.InputStream;
9import java.util.ArrayList;
10import java.util.Collection;
11import java.util.Collections;
12import java.util.HashSet;
13import java.util.LinkedList;
14import java.util.List;
15import java.util.Set;
16
17import org.junit.Rule;
18import org.junit.Test;
19import org.openstreetmap.josm.TestUtils;
20import org.openstreetmap.josm.data.osm.DataSet;
21import org.openstreetmap.josm.data.osm.Node;
22import org.openstreetmap.josm.data.osm.NodePair;
23import org.openstreetmap.josm.data.osm.Way;
24import org.openstreetmap.josm.io.IllegalDataException;
25import org.openstreetmap.josm.io.OsmReader;
26import org.openstreetmap.josm.testutils.JOSMTestRules;
27
28import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
29import nl.jqno.equalsverifier.EqualsVerifier;
30
31/**
32 * Unit tests for class {@link CombineWayAction}.
33 */
34public class CombineWayActionTest {
35
36 /**
37 * Setup test.
38 */
39 @Rule
40 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
41 public JOSMTestRules test = new JOSMTestRules();
42
43 /**
44 * Non-regression test for bug #11957.
45 * @throws IOException if any I/O error occurs
46 * @throws IllegalDataException if OSM parsing fails
47 */
48 @Test
49 public void testTicket11957() throws IOException, IllegalDataException {
50 try (InputStream is = TestUtils.getRegressionDataStream(11957, "data.osm")) {
51 DataSet ds = OsmReader.parseDataSet(is, null);
52 List<Node> path = CombineWayAction.tryJoin(ds.getWays());
53 assertEquals(10, path.size());
54 Set<Long> firstAndLastObtained = new HashSet<>();
55 firstAndLastObtained.add(path.get(0).getId());
56 firstAndLastObtained.add(path.get(path.size()-1).getId());
57 Set<Long> firstAndLastExpected = new HashSet<>();
58 firstAndLastExpected.add(1618969016L);
59 firstAndLastExpected.add(35213705L);
60 assertEquals(firstAndLastExpected, firstAndLastObtained);
61 }
62 }
63
64 /**
65 * Non-regression test for bug #18385 (combine way with overlapping ways)
66 * @throws IOException if any I/O error occurs
67 * @throws IllegalDataException if OSM parsing fails
68 */
69 @Test
70 public void testTicket18385() throws IOException, IllegalDataException {
71 try (InputStream is = TestUtils.getRegressionDataStream(18385, "data.osm")) {
72 DataSet ds = OsmReader.parseDataSet(is, null);
73 List<Node> path = CombineWayAction.tryJoin(ds.getWays());
74 assertFalse(path.isEmpty());
75 }
76 }
77
78 /**
79 * Non-regression test for bug #18387 (combine new way with oneway)
80 * @throws IOException if any I/O error occurs
81 * @throws IllegalDataException if OSM parsing fails
82 */
83 @Test
84 public void testTicket18387() throws IOException, IllegalDataException {
85 try (InputStream is = TestUtils.getRegressionDataStream(18387, "data.osm")) {
86 DataSet ds = OsmReader.parseDataSet(is, null);
87 ArrayList<Way> selection = new ArrayList<>(ds.getWays());
88 assertEquals(2, selection.size());
89 if (!selection.get(0).isNew())
90 Collections.reverse(selection);
91 double expectedLen = getOriginalLength(selection);
92 List<Node> path = CombineWayAction.tryJoin(selection);
93 assertFalse(path.isEmpty());
94 Way combined = new Way(0);
95 combined.setNodes(path);
96 assertEquals(expectedLen, combined.getLength(), 0.01);
97 }
98 }
99
100 /**
101 * Non-regression test for bug #18367 (Lines cannot be combined when they share an overlapping segment)
102 * @throws IOException if any I/O error occurs
103 * @throws IllegalDataException if OSM parsing fails
104 */
105 @Test
106 public void testTicket18367() throws IOException, IllegalDataException {
107 try (InputStream is = TestUtils.getRegressionDataStream(18367, "nocombine.osm")) {
108 DataSet ds = OsmReader.parseDataSet(is, null);
109 ArrayList<Way> selection = new ArrayList<>(ds.getWays());
110 assertEquals(2, selection.size());
111 double expectedLen = getOriginalLength(selection);
112 List<Node> path = CombineWayAction.tryJoin(selection);
113 assertFalse(path.isEmpty());
114 Way combined = new Way(0);
115 combined.setNodes(path);
116 assertEquals(expectedLen, combined.getLength(), 1e-7);
117 }
118 }
119
120
121 /**
122 * Non-regression test for bug #18367
123 * @throws IOException if any I/O error occurs
124 * @throws IllegalDataException if OSM parsing fails
125 */
126 @Test
127 public void testTicket18367NeedsSplit() throws IOException, IllegalDataException {
128 try (InputStream is = TestUtils.getRegressionDataStream(18367, "split-and-reverse.osm")) {
129 DataSet ds = OsmReader.parseDataSet(is, null);
130 ArrayList<Way> selection = new ArrayList<>(ds.getWays());
131 assertEquals(2, selection.size());
132 double expectedLen = getOriginalLength(selection);
133 List<Node> path = CombineWayAction.tryJoin(selection);
134 assertFalse(path.isEmpty());
135 Way combined = new Way(0);
136 combined.setNodes(path);
137 assertEquals(expectedLen, combined.getLength(), 1e-7);
138 List<Way> reversedWays = new LinkedList<>();
139 List<Way> unreversedWays = new LinkedList<>();
140 CombineWayAction.detectReversedWays(selection, path, reversedWays, unreversedWays);
141 assertFalse(reversedWays.isEmpty());
142 }
143 }
144
145
146 /**
147 * Test for bad reverse way detection. See #18367
148 * @throws IOException if any I/O error occurs
149 * @throws IllegalDataException if OSM parsing fails
150 */
151 @Test
152 public void testDetectReversedWays() throws IOException, IllegalDataException {
153 try (InputStream is = TestUtils.getRegressionDataStream(18367, "silent-revert.osm")) {
154 DataSet ds = OsmReader.parseDataSet(is, null);
155 ArrayList<Way> selection = new ArrayList<>(ds.getWays());
156 assertEquals(2, selection.size());
157 // make sure that short way is first
158 if (selection.get(0).getNodesCount() != 2)
159 Collections.reverse(selection);
160 double expectedLen = getOriginalLength(selection);
161 List<Node> path = CombineWayAction.tryJoin(selection);
162 assertFalse(path.isEmpty());
163 Way combined = new Way(0);
164 combined.setNodes(path);
165 assertEquals(expectedLen, combined.getLength(), 1e-7);
166 List<Way> reversedWays = new LinkedList<>();
167 List<Way> unreversedWays = new LinkedList<>();
168 CombineWayAction.detectReversedWays(selection, path, reversedWays, unreversedWays);
169 assertFalse(reversedWays.contains(selection.get(0)));
170 }
171 }
172
173
174 /**
175 * Unit test of methods {@link NodePair#equals} and {@link NodePair#hashCode}.
176 */
177 @Test
178 public void testEqualsContract() {
179 TestUtils.assumeWorkingEqualsVerifier();
180 EqualsVerifier.forClass(NodePair.class).usingGetClass()
181 .withPrefabValues(Node.class, new Node(1), new Node(2))
182 .verify();
183 }
184
185 private static double getOriginalLength(Collection<Way> ways) {
186 double len = 0;
187 for (Way w : ways) {
188 len += w.getLength();
189 }
190 return len;
191 }
192
193}
Note: See TracBrowser for help on using the repository browser.