source: josm/trunk/test/unit/org/openstreetmap/josm/command/SplitWayCommandTest.java@ 17275

Last change on this file since 17275 was 17275, checked in by Don-vip, 3 years ago

see #16567 - upgrade almost all tests to JUnit 5, except those depending on WiremockRule

See https://github.com/tomakehurst/wiremock/issues/684

File size: 17.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.command;
3
4import static org.junit.jupiter.api.Assertions.assertEquals;
5import static org.junit.jupiter.api.Assertions.assertFalse;
6import static org.junit.jupiter.api.Assertions.assertTrue;
7
8import java.io.IOException;
9import java.io.InputStream;
10import java.util.ArrayList;
11import java.util.Arrays;
12import java.util.Collections;
13import java.util.Iterator;
14import java.util.Optional;
15
16import org.junit.jupiter.api.Test;
17import org.junit.jupiter.api.extension.RegisterExtension;
18import org.openstreetmap.josm.TestUtils;
19import org.openstreetmap.josm.command.SplitWayCommand.Strategy;
20import org.openstreetmap.josm.data.UndoRedoHandler;
21import org.openstreetmap.josm.data.coor.LatLon;
22import org.openstreetmap.josm.data.osm.DataSet;
23import org.openstreetmap.josm.data.osm.Node;
24import org.openstreetmap.josm.data.osm.OsmPrimitive;
25import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
26import org.openstreetmap.josm.data.osm.Relation;
27import org.openstreetmap.josm.data.osm.RelationMember;
28import org.openstreetmap.josm.data.osm.Way;
29import org.openstreetmap.josm.io.IllegalDataException;
30import org.openstreetmap.josm.io.OsmReader;
31import org.openstreetmap.josm.testutils.JOSMTestRules;
32
33import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
34
35/**
36 * Unit tests for class {@link SplitWayCommand}.
37 */
38final class SplitWayCommandTest {
39
40 /**
41 * Setup test.
42 */
43 @RegisterExtension
44 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
45 public JOSMTestRules test = new JOSMTestRules().main().projection().preferences();
46
47 /**
48 * Unit test of {@link SplitWayCommand#findVias}.
49 */
50 @Test
51 void testFindVias() {
52 // empty relation
53 assertTrue(SplitWayCommand.findVias(new Relation(), null).isEmpty());
54 // restriction relation without via member
55 Relation r = new Relation();
56 r.addMember(new RelationMember("", new Node()));
57 assertTrue(SplitWayCommand.findVias(r, "restriction").isEmpty());
58 // restriction relation with via member
59 r = new Relation();
60 OsmPrimitive via = new Node();
61 r.addMember(new RelationMember("via", via));
62 assertEquals(Collections.singletonList(via), SplitWayCommand.findVias(r, "restriction"));
63 // destination_sign relation without sign nor intersection
64 r = new Relation();
65 r.addMember(new RelationMember("", new Node()));
66 assertTrue(SplitWayCommand.findVias(r, "destination_sign").isEmpty());
67 // destination_sign with sign
68 r = new Relation();
69 via = new Node();
70 r.addMember(new RelationMember("sign", via));
71 assertEquals(Collections.singletonList(via), SplitWayCommand.findVias(r, "destination_sign"));
72 // destination_sign with intersection
73 r = new Relation();
74 via = new Node();
75 r.addMember(new RelationMember("intersection", via));
76 assertEquals(Collections.singletonList(via), SplitWayCommand.findVias(r, "destination_sign"));
77 }
78
79 /**
80 * Unit tests of route relations.
81 */
82 @Test
83 void testRouteRelation() {
84 doTestRouteRelation(false, 0);
85 doTestRouteRelation(false, 1);
86 doTestRouteRelation(false, 2);
87 doTestRouteRelation(false, 3);
88 doTestRouteRelation(true, 0);
89 doTestRouteRelation(true, 1);
90 doTestRouteRelation(true, 2);
91 doTestRouteRelation(true, 3);
92 }
93
94 void doTestRouteRelation(final boolean wayIsReversed, final int indexOfWayToKeep) {
95 final DataSet dataSet = new DataSet();
96 final Node n1 = new Node(new LatLon(1, 0));
97 final Node n2 = new Node(new LatLon(2, 0));
98 final Node n3 = new Node(new LatLon(3, 0));
99 final Node n4 = new Node(new LatLon(4, 0));
100 final Node n5 = new Node(new LatLon(5, 0));
101 final Node n6 = new Node(new LatLon(6, 0));
102 final Node n7 = new Node(new LatLon(7, 0));
103 final Way w1 = new Way();
104 final Way w2 = new Way();
105 final Way w3 = new Way();
106 final Relation route = new Relation();
107 for (OsmPrimitive p : Arrays.asList(n1, n2, n3, n4, n5, n6, n7, w1, w2, w3, route)) {
108 dataSet.addPrimitive(p);
109 }
110 w1.setNodes(Arrays.asList(n1, n2));
111 w2.setNodes(wayIsReversed
112 ? Arrays.asList(n6, n5, n4, n3, n2)
113 : Arrays.asList(n2, n3, n4, n5, n6)
114 );
115 w3.setNodes(Arrays.asList(n6, n7));
116 route.put("type", "route");
117 route.addMember(new RelationMember("", w1));
118 route.addMember(new RelationMember("", w2));
119 route.addMember(new RelationMember("", w3));
120 dataSet.setSelected(Arrays.asList(w2, n3, n4, n5));
121
122 final Strategy strategy = wayChunks -> {
123 final Iterator<Way> it = wayChunks.iterator();
124 for (int i = 0; i < indexOfWayToKeep; i++) {
125 it.next();
126 }
127 return it.next();
128 };
129 final SplitWayCommand result = SplitWayCommand.splitWay(
130 w2, SplitWayCommand.buildSplitChunks(w2, Arrays.asList(n3, n4, n5)), new ArrayList<>(), strategy);
131 UndoRedoHandler.getInstance().add(result);
132
133 assertEquals(6, route.getMembersCount());
134 assertEquals(w1, route.getMemberPrimitivesList().get(0));
135 assertEquals(w3, route.getMemberPrimitivesList().get(5));
136 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(0)), n1);
137 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(0)), n2);
138 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(1)), n2);
139 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(1)), n3);
140 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(2)), n3);
141 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(2)), n4);
142 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(3)), n4);
143 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(3)), n5);
144 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(4)), n5);
145 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(4)), n6);
146 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(5)), n6);
147 assertFirstLastNodeIs(((Way) route.getMemberPrimitivesList().get(5)), n7);
148 }
149
150 @Test
151 void testOneMemberOrderedRelationShowsWarningTest() {
152 final DataSet dataSet = new DataSet();
153
154 // Positive IDs to mark that these ways are incomplete (i.e., no nodes loaded).
155 final Way w1 = new Way(1);
156 final Way w3 = new Way(3);
157
158 // The way we are going to split is complete of course.
159 final Node n1 = new Node(new LatLon(1, 0));
160 final Node n2 = new Node(new LatLon(2, 0));
161 final Node n3 = new Node(new LatLon(3, 0));
162 final Way w2 = new Way();
163
164 final Relation route = new Relation();
165 for (OsmPrimitive p : Arrays.asList(n1, n2, n3, w1, w2, w3, route)) {
166 dataSet.addPrimitive(p);
167 }
168 w2.setNodes(Arrays.asList(n1, n2, n3));
169
170 route.put("type", "route");
171 route.addMember(new RelationMember("", w1));
172 route.addMember(new RelationMember("", w2));
173 route.addMember(new RelationMember("", w3));
174 dataSet.setSelected(Arrays.asList(w2, n2));
175
176 // This split cannot be safely performed without downloading extra relation members.
177 // Here we ask the split method to abort if it needs more information.
178 final Optional<SplitWayCommand> result = SplitWayCommand.splitWay(
179 w2,
180 SplitWayCommand.buildSplitChunks(w2, Collections.singletonList(n2)),
181 new ArrayList<>(),
182 Strategy.keepLongestChunk(),
183 SplitWayCommand.WhenRelationOrderUncertain.ABORT
184 );
185
186 assertFalse(result.isPresent());
187 }
188
189 @Test
190 void testDoIncompleteMembersOrderedRelationCorrectOrderTest() {
191 for (int i = 0; i < 2; i++) {
192 // All these permutations should result in a split that keeps the new parts in order.
193 doIncompleteMembersOrderedRelationCorrectOrderTest(false, false, i);
194 doIncompleteMembersOrderedRelationCorrectOrderTest(true, false, i);
195 doIncompleteMembersOrderedRelationCorrectOrderTest(true, true, i);
196 doIncompleteMembersOrderedRelationCorrectOrderTest(false, true, i);
197 }
198 }
199
200 private void doIncompleteMembersOrderedRelationCorrectOrderTest(final boolean reverseWayOne,
201 final boolean reverseWayTwo,
202 final int indexOfWayToKeep) {
203 final DataSet dataSet = new DataSet();
204
205 // Positive IDs to mark that these ways are incomplete (i.e., no nodes loaded).
206 final Way w1 = new Way(1);
207 final Way w4 = new Way(3);
208
209 // The ways we are going to split are complete of course.
210 final Node n1 = new Node(new LatLon(1, 0));
211 final Node n2 = new Node(new LatLon(2, 0));
212 final Node n3 = new Node(new LatLon(3, 0));
213 final Node n4 = new Node(new LatLon(4, 0));
214 final Node n5 = new Node(new LatLon(5, 0));
215 final Way w2 = new Way();
216 final Way w3 = new Way();
217
218 final Relation route = new Relation();
219 for (OsmPrimitive p : Arrays.asList(n1, n2, n3, n4, n5, w1, w2, w3, w4, route)) {
220 dataSet.addPrimitive(p);
221 }
222 w2.setNodes(reverseWayOne ? Arrays.asList(n3, n2, n1) : Arrays.asList(n1, n2, n3));
223 w3.setNodes(reverseWayTwo ? Arrays.asList(n5, n4, n3) : Arrays.asList(n3, n4, n5));
224
225 route.put("type", "route");
226 route.addMember(new RelationMember("", w1));
227 route.addMember(new RelationMember("", w2));
228 route.addMember(new RelationMember("", w3));
229 route.addMember(new RelationMember("", w4));
230
231 Way splitWay = indexOfWayToKeep == 0 ? w2 : w3;
232 Node splitNode = indexOfWayToKeep == 0 ? n2 : n4;
233
234 dataSet.setSelected(Arrays.asList(splitWay, splitNode));
235
236 final SplitWayCommand result = SplitWayCommand.splitWay(
237 splitWay, SplitWayCommand.buildSplitChunks(splitWay, Collections.singletonList(splitNode)), new ArrayList<>());
238 UndoRedoHandler.getInstance().add(result);
239
240 assertEquals(5, route.getMembersCount());
241 assertConnectedAtEnds(route.getMember(1).getWay(), route.getMember(2).getWay());
242 assertConnectedAtEnds(route.getMember(2).getWay(), route.getMember(3).getWay());
243 }
244
245 static void assertFirstLastNodeIs(Way way, Node node) {
246 assertTrue(node.equals(way.firstNode()) || node.equals(way.lastNode()),
247 "First/last node of " + way + " should be " + node);
248 }
249
250 static void assertConnectedAtEnds(Way one, Way two) {
251 Node first1 = one.firstNode();
252 Node last1 = one.lastNode();
253 Node first2 = two.firstNode();
254 Node last2 = two.lastNode();
255
256 assertTrue(first1 == first2 || first1 == last2 || last1 == first2 || last1 == last2,
257 "Ways expected to be connected at their ends.");
258 }
259
260 /**
261 * Non-regression test for patch #18596 (Fix relation ordering after split-way)
262 * @throws IOException if any I/O error occurs
263 * @throws IllegalDataException if OSM parsing fails
264 */
265 @Test
266 void testTicket18596() throws IOException, IllegalDataException {
267 try (InputStream is = TestUtils.getRegressionDataStream(18596, "data.osm")) {
268 DataSet ds = OsmReader.parseDataSet(is, null);
269
270 Way splitWay = (Way) ds.getPrimitiveById(5, OsmPrimitiveType.WAY);
271 Node splitNode = (Node) ds.getPrimitiveById(100002, OsmPrimitiveType.NODE);
272
273 final SplitWayCommand result = SplitWayCommand.splitWay(
274 splitWay,
275 SplitWayCommand.buildSplitChunks(splitWay, Collections.singletonList(splitNode)),
276 new ArrayList<>()
277 );
278
279 UndoRedoHandler.getInstance().add(result);
280
281 Relation relation = (Relation) ds.getPrimitiveById(8888, OsmPrimitiveType.RELATION);
282
283 assertEquals(8, relation.getMembersCount());
284
285 // Before the patch introduced in #18596, these asserts would fail. The two parts of
286 // way '5' would be in the wrong order, breaking the boundary relation in this test.
287 assertConnectedAtEnds(relation.getMember(4).getWay(), relation.getMember(5).getWay());
288 assertConnectedAtEnds(relation.getMember(5).getWay(), relation.getMember(6).getWay());
289 }
290 }
291
292 /**
293 * Non-regression test for issue #17400 (Warn when splitting way in not fully downloaded region)
294 *
295 * Bus route 190 gets broken when the split occurs, because the two new way parts are inserted in the relation in
296 * the wrong order.
297 *
298 * @throws IOException if any I/O error occurs
299 * @throws IllegalDataException if OSM parsing fails
300 */
301 @Test
302 void testTicket17400() throws IOException, IllegalDataException {
303 try (InputStream is = TestUtils.getRegressionDataStream(17400, "data.osm")) {
304 DataSet ds = OsmReader.parseDataSet(is, null);
305
306 Way splitWay = (Way) ds.getPrimitiveById(253731928, OsmPrimitiveType.WAY);
307 Node splitNode = (Node) ds.getPrimitiveById(29830834, OsmPrimitiveType.NODE);
308
309 final Optional<SplitWayCommand> result = SplitWayCommand.splitWay(
310 splitWay,
311 SplitWayCommand.buildSplitChunks(splitWay, Collections.singletonList(splitNode)),
312 new ArrayList<>(),
313 Strategy.keepLongestChunk(),
314 // This split requires no additional downloads.
315 SplitWayCommand.WhenRelationOrderUncertain.ABORT
316 );
317
318 assertTrue(result.isPresent());
319
320 UndoRedoHandler.getInstance().add(result.get());
321
322 // 190 Hormersdorf-Thalheim-Stollberg.
323 Relation relation = (Relation) ds.getPrimitiveById(2873422, OsmPrimitiveType.RELATION);
324
325 // One more than the original 161.
326 assertEquals(162, relation.getMembersCount());
327
328 // Before the patch introduced in #18596, these asserts would fail. The new parts of
329 // the Hauptstraße would be in the wrong order, breaking the bus route relation.
330 // These parts should be connected, in their relation sequence: 74---75---76.
331 // Before #18596 this would have been a broken connection: 74---75-x-76.
332 assertConnectedAtEnds(relation.getMember(74).getWay(), relation.getMember(75).getWay());
333 assertConnectedAtEnds(relation.getMember(75).getWay(), relation.getMember(76).getWay());
334 }
335 }
336
337 /**
338 * Non-regression test for issue #18863 (Asking for download of missing members when not needed)
339 *
340 * A split on node 4518025255 caused the 'download missing members?' dialog to pop up for relation 68745 (CB 2),
341 * even though the way members next to the split way were already downloaded. This happened because this relation
342 * does not have its members connected at all.
343 *
344 * This split should not trigger any download action at all.
345 *
346 * @throws IOException if any I/O error occurs
347 * @throws IllegalDataException if OSM parsing fails
348 */
349 @Test
350 void testTicket18863() throws IOException, IllegalDataException {
351 try (InputStream is = TestUtils.getRegressionDataStream(18863, "data.osm.bz2")) {
352 DataSet ds = OsmReader.parseDataSet(is, null);
353
354 Way splitWay = (Way) ds.getPrimitiveById(290581177L, OsmPrimitiveType.WAY);
355 Node splitNode = (Node) ds.getPrimitiveById(4518025255L, OsmPrimitiveType.NODE);
356
357 final Optional<SplitWayCommand> result = SplitWayCommand.splitWay(
358 splitWay,
359 SplitWayCommand.buildSplitChunks(splitWay, Collections.singletonList(splitNode)),
360 new ArrayList<>(),
361 Strategy.keepLongestChunk(),
362 // This split requires no additional downloads. If any are needed, this command will fail.
363 SplitWayCommand.WhenRelationOrderUncertain.ABORT
364 );
365
366 // Should not result in aborting the split.
367 assertTrue(result.isPresent());
368 }
369 }
370
371 /**
372 * Non-regression test for issue #19432 (AIOOB: Problem with member check with duplicate members)
373 *
374 * @throws IOException if any I/O error occurs
375 * @throws IllegalDataException if OSM parsing fails
376 */
377 @Test
378 void testTicket19432() throws IOException, IllegalDataException {
379 try (InputStream is = TestUtils.getRegressionDataStream(19432, "josm_split_way_exception_example.osm.bz2")) {
380 DataSet ds = OsmReader.parseDataSet(is, null);
381
382 Way splitWay = (Way) ds.getPrimitiveById(632576744L, OsmPrimitiveType.WAY);
383 Node splitNode = (Node) ds.getPrimitiveById(1523436358L, OsmPrimitiveType.NODE);
384
385 final Optional<SplitWayCommand> result = SplitWayCommand.splitWay(
386 splitWay,
387 SplitWayCommand.buildSplitChunks(splitWay, Collections.singletonList(splitNode)),
388 new ArrayList<>(),
389 Strategy.keepLongestChunk(),
390 // This split requires additional downloads but problem occured before the download
391 SplitWayCommand.WhenRelationOrderUncertain.SPLIT_ANYWAY
392 );
393
394 // Should not result in aborting the split.
395 assertTrue(result.isPresent());
396 }
397 }
398}
Note: See TracBrowser for help on using the repository browser.