source: josm/trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetMergerTest.java@ 9979

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

see #12599, fix #12616 - Random repositioning of nodes (incomplete fix from r9961)

  • Property svn:eol-style set to native
File size: 31.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.osm;
3
4import static org.junit.Assert.assertEquals;
5import static org.junit.Assert.assertFalse;
6import static org.junit.Assert.assertNotNull;
7import static org.junit.Assert.assertNotSame;
8import static org.junit.Assert.assertSame;
9import static org.junit.Assert.assertTrue;
10
11import java.io.StringWriter;
12import java.util.Arrays;
13import java.util.Calendar;
14import java.util.Date;
15import java.util.GregorianCalendar;
16
17import org.junit.After;
18import org.junit.Before;
19import org.junit.BeforeClass;
20import org.junit.Test;
21import org.openstreetmap.josm.JOSMFixture;
22import org.openstreetmap.josm.Main;
23import org.openstreetmap.josm.data.coor.LatLon;
24import org.openstreetmap.josm.data.projection.Projections;
25
26/**
27 * Unit tests for class {@link DataSetMerger}.
28 */
29public class DataSetMergerTest {
30
31 /**
32 * Setup test.
33 */
34 @BeforeClass
35 public static void init() {
36 JOSMFixture.createUnitTestFixture().init();
37 }
38
39 private DataSet my;
40 private DataSet their;
41
42 /**
43 * Setup test.
44 */
45 @Before
46 public void setUp() {
47 User.clearUserMap();
48 my = new DataSet();
49 my.setVersion("0.6");
50 their = new DataSet();
51 their.setVersion("0.6");
52 Main.setProjection(Projections.getProjectionByCode("EPSG:3857")); // Mercator
53 }
54
55 private void runConsistencyTests(DataSet ds) throws Exception {
56 StringWriter writer = new StringWriter();
57 DatasetConsistencyTest test = new DatasetConsistencyTest(ds, writer);
58 test.checkReferrers();
59 test.checkCompleteWaysWithIncompleteNodes();
60 test.searchNodes();
61 test.searchWays();
62 test.referredPrimitiveNotInDataset();
63 test.checkZeroNodesWays();
64 String result = writer.toString();
65 if (result.length() > 0)
66 throw new RuntimeException(result);
67 }
68
69 @After
70 public void checkDatasets() throws Exception {
71 runConsistencyTests(my);
72 runConsistencyTests(their);
73 }
74
75 /**
76 * two identical nodes, even in id and version. No confict expected.
77 *
78 * Can happen if data is loaded in two layers and then merged from one layer
79 * on the other.
80 */
81 @Test
82 public void nodeSimple_IdenticalNoConflict() {
83 Node n = new Node(LatLon.ZERO);
84 n.setOsmId(1, 1);
85 n.setModified(false);
86 n.put("key1", "value1");
87 my.addPrimitive(n);
88
89 Node n1 = new Node(LatLon.ZERO);
90 n1.setOsmId(1, 1);
91 n1.setModified(false);
92 n1.put("key1", "value1");
93 their.addPrimitive(n1);
94
95
96 DataSetMerger visitor = new DataSetMerger(my, their);
97 visitor.merge();
98
99 Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
100 assertTrue(visitor.getConflicts().isEmpty());
101 assertNotSame(n1, n2); // make sure we have a clone
102 assertEquals(1, n2.getId());
103 assertEquals(1, n2.getVersion());
104 assertFalse(n2.isModified());
105 assertEquals("value1", n2.get("key1"));
106
107 // merge target not modified after merging
108 assertFalse(n2.isModified());
109 }
110
111 /**
112 * two nodes, my is unmodified, their is updated and has a higher version
113 * => their version is going to be the merged version
114 *
115 */
116 @Test
117 public void nodeSimple_locallyUnmodifiedNoConflict() {
118 Node n = new Node(LatLon.ZERO);
119 n.setOsmId(1, 1);
120 n.setModified(false);
121 n.put("key1", "value1");
122 my.addPrimitive(n);
123
124 Node n1 = new Node(LatLon.ZERO);
125 n1.setOsmId(1, 2);
126 n1.setModified(false);
127 n1.put("key1", "value1-new");
128 n1.put("key2", "value2");
129 their.addPrimitive(n1);
130
131
132 DataSetMerger visitor = new DataSetMerger(my, their);
133 visitor.merge();
134
135 Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
136 assertTrue(visitor.getConflicts().isEmpty());
137 assertSame(n, n2); // make sure the merged node is still the original node
138 assertSame(n2.getDataSet(), my);
139 assertEquals(1, n2.getId());
140 assertEquals(2, n2.getVersion());
141 assertFalse(n2.isModified());
142 assertEquals("value1-new", n2.get("key1"));
143 assertEquals("value2", n2.get("key2"));
144
145 // the merge target should not be modified
146 assertFalse(n2.isModified());
147 }
148
149 /**
150 * Node with same id, my is modified, their has a higher version
151 * => results in a conflict
152 *
153 * Use case: node which is modified locally and updated by another mapper on
154 * the server
155 */
156 @Test
157 public void nodeSimple_TagConflict() {
158 Node n = new Node(LatLon.ZERO);
159 n.setOsmId(1, 1);
160 n.setModified(true);
161 n.put("key1", "value1");
162 n.put("key2", "value2");
163 my.addPrimitive(n);
164
165 Node n1 = new Node(LatLon.ZERO);
166 n1.setOsmId(1, 2);
167 n1.setModified(false);
168 n1.put("key1", "value1-new");
169
170 their.addPrimitive(n1);
171
172
173 DataSetMerger visitor = new DataSetMerger(my, their);
174 visitor.merge();
175
176 Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
177 assertEquals(1, visitor.getConflicts().size());
178 assertSame(n, n2);
179 assertNotSame(n1, n2);
180 assertSame(n1.getDataSet(), their);
181 }
182
183 /**
184 * node with same id, my is deleted, their has a higher version
185 * => results in a conflict
186 *
187 * Use case: node which is deleted locally and updated by another mapper on
188 * the server
189 */
190 @Test
191 public void nodeSimple_DeleteConflict() {
192 Node n = new Node(1, 1);
193 n.setCoor(LatLon.ZERO);
194 n.setDeleted(true);
195 n.put("key1", "value1");
196 my.addPrimitive(n);
197
198 Node n1 = new Node(LatLon.ZERO);
199 n1.setOsmId(1, 2);
200 n1.setModified(false);
201 n1.put("key1", "value1-new");
202 n1.put("key2", "value2");
203 their.addPrimitive(n1);
204
205
206 DataSetMerger visitor = new DataSetMerger(my, their);
207 visitor.merge();
208
209 Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
210 assertEquals(1, visitor.getConflicts().size());
211 assertSame(n, n2);
212 assertNotSame(n1, n2);
213 assertSame(n1.getDataSet(), their);
214 }
215
216 /**
217 * My node is deleted, their node has the same id and version and is not deleted.
218 * => mine has precedence
219 *
220 */
221 @Test
222 public void nodeSimple_DeleteConflict_2() {
223 Node n = new Node(LatLon.ZERO);
224 n.setOsmId(1, 1);
225 n.setDeleted(true);
226 my.addPrimitive(n);
227
228 Node n1 = new Node(LatLon.ZERO);
229 n1.setOsmId(1, 1);
230 their.addPrimitive(n1);
231
232
233 DataSetMerger visitor = new DataSetMerger(my, their);
234 visitor.merge();
235
236 Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
237 assertEquals(0, visitor.getConflicts().size());
238 assertTrue(n2.isVisible());
239 assertSame(n, n2);
240 assertSame(n.getDataSet(), my);
241 assertSame(n1.getDataSet(), their);
242 }
243
244 /**
245 * My and their node are new but semantically equal. My node is deleted.
246 *
247 * => Ignore my node, no conflict
248 */
249 @Test
250 public void nodeSimple_DeleteConflict_3() {
251 Node n = new Node(new LatLon(1, 1));
252 n.setDeleted(true);
253 my.addPrimitive(n);
254
255 Node n1 = new Node(new LatLon(1, 1));
256 their.addPrimitive(n1);
257
258
259 DataSetMerger visitor = new DataSetMerger(my, their);
260 visitor.merge();
261
262 assertEquals(0, visitor.getConflicts().size());
263 assertSame(n.getDataSet(), my);
264 assertSame(n1.getDataSet(), their);
265 }
266
267 /**
268 * My and their node are new but semantically equal. Both are deleted.
269 *
270 * => take mine
271 *
272 */
273 @Test
274 public void nodeSimple_DeleteConflict_4() {
275 Node n = new Node(new LatLon(1, 1));
276 n.setDeleted(true);
277 my.addPrimitive(n);
278
279 Node n1 = new Node(new LatLon(1, 1));
280 n1.setDeleted(true);
281 their.addPrimitive(n1);
282
283
284 DataSetMerger visitor = new DataSetMerger(my, their);
285 visitor.merge();
286
287 assertEquals(0, visitor.getConflicts().size());
288 Node n2 = (Node) my.getNodes().toArray()[0];
289 assertSame(n2, n);
290 assertTrue(n2.isDeleted());
291 }
292
293 /**
294 * their node has no assigned id (id == 0) and is semantically equal to one of my
295 * nodes with id == 0
296 *
297 * => merge it onto my node.
298 *
299 */
300 @Test
301 public void nodeSimple_NoIdSemanticallyEqual() {
302
303 Calendar cal = GregorianCalendar.getInstance();
304 User myUser = User.createOsmUser(1111, "my");
305
306 User theirUser = User.createOsmUser(222, "their");
307
308 Node n = new Node();
309 n.setCoor(LatLon.ZERO);
310 n.put("key1", "value1");
311 n.setUser(myUser);
312 n.setTimestamp(cal.getTime());
313
314 my.addPrimitive(n);
315
316 Node n1 = new Node();
317 n1.setCoor(LatLon.ZERO);
318 n1.put("key1", "value1");
319 cal.add(Calendar.HOUR, 1);
320 Date timestamp = cal.getTime();
321 n1.setTimestamp(timestamp);
322 n1.setUser(theirUser);
323 their.addPrimitive(n1);
324
325 DataSetMerger visitor = new DataSetMerger(my, their);
326 visitor.merge();
327
328 Node n2 = my.getNodes().iterator().next();
329 assertEquals(0, visitor.getConflicts().size());
330 assertEquals("value1", n2.get("key1"));
331 assertEquals(n1.getRawTimestamp(), n2.getRawTimestamp());
332 assertEquals(theirUser, n2.getUser());
333 assertSame(n2, n);
334 assertNotSame(n2, n1);
335 assertSame(n2.getDataSet(), my);
336 }
337
338 /**
339 * my node is incomplete, their node is complete
340 *
341 * => merge it onto my node. My node becomes complete
342 *
343 */
344 @Test
345 public void nodeSimple_IncompleteNode() {
346
347 Node n = new Node(1);
348 my.addPrimitive(n);
349
350 Node n1 = new Node();
351 n1.setCoor(LatLon.ZERO);
352 n1.setOsmId(1, 1);
353 n1.put("key1", "value1");
354 Date timestamp = new Date();
355 n1.setTimestamp(timestamp);
356 their.addPrimitive(n1);
357
358 DataSetMerger visitor = new DataSetMerger(my, their);
359 visitor.merge();
360
361 Node n2 = my.getNodes().iterator().next();
362 assertEquals(0, visitor.getConflicts().size());
363 assertEquals("value1", n2.get("key1"));
364 assertEquals(n1.getRawTimestamp(), n2.getRawTimestamp());
365 assertFalse(n2.isIncomplete());
366 assertSame(n2, n);
367 }
368
369 /**
370 * their way has a higher version and different tags. the nodes are the same. My
371 * way is not modified. Merge is possible. No conflict.
372 *
373 * => merge it onto my way.
374 *
375 */
376 @Test
377 public void waySimple_IdenicalNodesDifferentTags() {
378
379 // -- the target dataset
380
381 Node n1 = new Node();
382 n1.setCoor(LatLon.ZERO);
383 n1.setOsmId(1, 1);
384 my.addPrimitive(n1);
385
386 Node n2 = new Node();
387 n2.setCoor(LatLon.ZERO);
388 n2.setOsmId(2, 1);
389
390 my.addPrimitive(n2);
391
392 Way myWay = new Way();
393 myWay.setOsmId(3, 1);
394 myWay.put("key1", "value1");
395 myWay.addNode(n1);
396 myWay.addNode(n2);
397 my.addPrimitive(myWay);
398
399 // -- the source data set
400
401 Node n3 = new Node(LatLon.ZERO);
402 n3.setOsmId(1, 1);
403 their.addPrimitive(n3);
404
405 Node n4 = new Node(new LatLon(1, 1));
406 n4.setOsmId(2, 1);
407 their.addPrimitive(n4);
408
409 Way theirWay = new Way();
410 theirWay.setOsmId(3, 2);
411 theirWay.put("key1", "value1");
412 theirWay.put("key2", "value2");
413 theirWay.addNode(n3);
414 theirWay.addNode(n4);
415 their.addPrimitive(theirWay);
416
417
418 DataSetMerger visitor = new DataSetMerger(my, their);
419 visitor.merge();
420
421 // -- tests
422 Way merged = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
423 assertEquals(0, visitor.getConflicts().size());
424 assertEquals("value1", merged.get("key1"));
425 assertEquals("value2", merged.get("key2"));
426 assertEquals(3, merged.getId());
427 assertEquals(2, merged.getVersion());
428 assertEquals(2, merged.getNodesCount());
429 assertEquals(1, merged.getNode(0).getId());
430 assertEquals(2, merged.getNode(1).getId());
431 assertSame(merged, myWay);
432 assertSame(merged.getDataSet(), my);
433
434 Node mergedNode = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
435 assertSame(mergedNode, n1);
436 mergedNode = (Node) my.getPrimitiveById(2, OsmPrimitiveType.NODE);
437 assertSame(mergedNode, n2);
438
439 assertFalse(merged.isModified());
440 }
441
442 /**
443 * their way has a higher version and different tags. And it has more nodes. Two
444 * of the existing nodes are modified.
445 *
446 * => merge it onto my way, no conflict
447 *
448 */
449 @Test
450 public void waySimple_AdditionalNodesAndChangedNodes() {
451
452 // -- my data set
453
454 Node n1 = new Node(LatLon.ZERO);
455 n1.setOsmId(1, 1);
456 my.addPrimitive(n1);
457
458 Node n2 = new Node(new LatLon(1, 1));
459 n2.setOsmId(2, 1);
460 my.addPrimitive(n2);
461
462 Way myWay = new Way();
463 myWay.setOsmId(3, 1);
464 myWay.addNode(n1);
465 myWay.addNode(n2);
466 my.addPrimitive(myWay);
467
468 // --- their data set
469
470 Node n3 = new Node(LatLon.ZERO);
471 n3.setOsmId(1, 1);
472 their.addPrimitive(n3);
473
474 Node n5 = new Node(new LatLon(1, 1));
475 n5.setOsmId(4, 1);
476
477 their.addPrimitive(n5);
478
479 Node n4 = new Node(new LatLon(2, 2));
480 n4.setOsmId(2, 2);
481 n4.put("key1", "value1");
482 their.addPrimitive(n4);
483
484
485 Way theirWay = new Way();
486 theirWay.setOsmId(3, 2);
487 theirWay.addNode(n3);
488 theirWay.addNode(n5); // insert a node
489 theirWay.addNode(n4); // this one is updated
490 their.addPrimitive(theirWay);
491
492 DataSetMerger visitor = new DataSetMerger(my, their);
493 visitor.merge();
494
495 // -- tests
496 Way merged = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
497 assertEquals(0, visitor.getConflicts().size());
498 assertEquals(3, merged.getId());
499 assertEquals(2, merged.getVersion());
500 assertEquals(3, merged.getNodesCount());
501 assertEquals(1, merged.getNode(0).getId());
502 assertEquals(4, merged.getNode(1).getId());
503 assertEquals(2, merged.getNode(2).getId());
504 assertEquals("value1", merged.getNode(2).get("key1"));
505
506 assertSame(merged.getNode(0), n1);
507 assertNotSame(merged.getNode(1), n5); // must be clone of the original node in their
508 assertSame(merged.getNode(2), n2);
509
510 assertFalse(merged.isModified()); // the target wasn't modified before merging, it mustn't be after merging
511 }
512
513 /**
514 * their way has a higher version and different nodes. My way is modified.
515 *
516 * => merge onto my way not possible, create a conflict
517 *
518 */
519 @Test
520 public void waySimple_DifferentNodesAndMyIsModified() {
521
522 // -- the target dataset
523
524 Node n1 = new Node(LatLon.ZERO);
525 n1.setOsmId(1, 1);
526 my.addPrimitive(n1);
527
528 Node n2 = new Node(new LatLon(1, 1));
529 n2.setOsmId(2, 1);
530 my.addPrimitive(n2);
531
532 Way myWay = new Way();
533 myWay.setOsmId(3, 1);
534
535 myWay.addNode(n1);
536 myWay.addNode(n2);
537 myWay.setModified(true);
538 myWay.put("key1", "value1");
539 my.addPrimitive(myWay);
540
541 // -- the source dataset
542
543 Node n3 = new Node(LatLon.ZERO);
544 n3.setOsmId(1, 1);
545 their.addPrimitive(n3);
546
547 Node n5 = new Node(new LatLon(1, 1));
548 n5.setOsmId(4, 1);
549 their.addPrimitive(n5);
550
551 Node n4 = new Node(new LatLon(2, 2));
552 n4.setOsmId(2, 1);
553 n4.put("key1", "value1");
554 their.addPrimitive(n4);
555
556 Way theirWay = new Way();
557 theirWay.setOsmId(3, 2);
558
559 theirWay.addNode(n3);
560 theirWay.addNode(n5); // insert a node
561 theirWay.addNode(n4); // this one is updated
562 their.addPrimitive(theirWay);
563
564
565 DataSetMerger visitor = new DataSetMerger(my, their);
566 visitor.merge();
567
568 Way merged = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
569 assertEquals(1, visitor.getConflicts().size());
570 assertEquals(3, merged.getId());
571 assertEquals(1, merged.getVersion());
572 assertEquals(2, merged.getNodesCount());
573 assertEquals(1, merged.getNode(0).getId());
574 assertEquals(2, merged.getNode(1).getId());
575 assertEquals("value1", merged.get("key1"));
576 }
577
578 /**
579 * their way is not visible anymore.
580 *
581 * => conflict
582 *
583 */
584 @Test
585 public void waySimple_TheirVersionNotVisibleMyIsModified() {
586
587 Node mn1 = new Node(LatLon.ZERO);
588 mn1.setOsmId(1, 1);
589 my.addPrimitive(mn1);
590
591 Node mn2 = new Node(new LatLon(1, 1));
592 mn2.setOsmId(2, 1);
593 my.addPrimitive(mn2);
594
595 Way myWay = new Way();
596 myWay.setOsmId(3, 1);
597 myWay.addNode(mn1);
598 myWay.addNode(mn2);
599 myWay.setModified(true);
600 my.addPrimitive(myWay);
601
602 Way theirWay = new Way();
603 theirWay.setOsmId(3, 2);
604 theirWay.setVisible(false);
605 /* Invisible objects fetched from the server should be marked as "deleted".
606 * Otherwise it's an error.
607 */
608 theirWay.setDeleted(true);
609 their.addPrimitive(theirWay);
610
611 DataSetMerger visitor = new DataSetMerger(my, their);
612 visitor.merge();
613
614 Way merged = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
615 assertEquals(1, visitor.getConflicts().size());
616 assertTrue(visitor.getConflicts().hasConflictForMy(myWay));
617 assertTrue(visitor.getConflicts().hasConflictForTheir(theirWay));
618 assertEquals(myWay, merged);
619 }
620
621 /**
622 * my and their way have no ids, nodes they refer to have an id. but
623 * my and their way are semantically equal. so technical attributes of
624 * their way can be merged on my way. No conflict.
625 *
626 */
627 @Test
628 public void waySimple_twoWaysWithNoId_NodesWithId() {
629
630 // -- my data set
631
632 Node n1 = new Node(LatLon.ZERO);
633 n1.setOsmId(1, 1);
634 my.addPrimitive(n1);
635
636 Node n2 = new Node(new LatLon(1, 1));
637 n2.setOsmId(2, 1);
638 my.addPrimitive(n2);
639
640 Way myWay = new Way();
641 myWay.addNode(n1);
642 myWay.addNode(n2);
643 my.addPrimitive(myWay);
644
645 // -- their data set
646
647 Node n3 = new Node(LatLon.ZERO);
648 n3.setOsmId(1, 1);
649 their.addPrimitive(n3);
650
651 Node n4 = new Node(new LatLon(1, 1));
652 n4.setOsmId(2, 1);
653 their.addPrimitive(n4);
654
655 Way theirWay = new Way();
656 theirWay.addNode(n3);
657 theirWay.addNode(n4);
658 User user = User.createOsmUser(1111, "their");
659 theirWay.setUser(user);
660 theirWay.setTimestamp(new Date());
661 their.addPrimitive(theirWay);
662
663 DataSetMerger visitor = new DataSetMerger(my, their);
664 visitor.merge();
665
666 // -- tests
667 Way merged = (Way) my.getWays().toArray()[0];
668 assertEquals(0, visitor.getConflicts().size());
669 assertEquals("their", merged.getUser().getName());
670 assertEquals(1111, merged.getUser().getId());
671 assertEquals(theirWay.getRawTimestamp(), merged.getRawTimestamp());
672 assertSame(merged, myWay);
673 assertSame(merged.getNode(0), n1);
674 assertSame(merged.getNode(1), n2);
675
676 assertFalse(merged.isModified());
677 }
678
679 /**
680 * my and their way have no ids, neither do the nodes they refer to. but
681 * my and their way are semantically equal. so technical attributes of
682 * their way can be merged on my way. No conflict.
683 *
684 */
685 @Test
686 public void waySimple_twoWaysWithNoId_NodesWithoutId() {
687
688 // -- my data set
689
690 Node n1 = new Node(LatLon.ZERO);
691 my.addPrimitive(n1);
692
693 Node n2 = new Node(new LatLon(1, 1));
694 my.addPrimitive(n2);
695
696 Way myWay = new Way();
697 myWay.addNode(n1);
698 myWay.addNode(n2);
699 my.addPrimitive(myWay);
700
701 // -- their data set
702
703 Node n3 = new Node(LatLon.ZERO);
704 their.addPrimitive(n3);
705
706 Node n4 = new Node(new LatLon(1, 1));
707 their.addPrimitive(n4);
708
709 Way theirWay = new Way();
710 theirWay.addNode(n3);
711 theirWay.addNode(n4);
712 User user = User.createOsmUser(1111, "their");
713 theirWay.setUser(user);
714 theirWay.setTimestamp(new Date());
715 their.addPrimitive(theirWay);
716
717 DataSetMerger visitor = new DataSetMerger(my, their);
718 visitor.merge();
719
720 // -- tests
721 Way merged = (Way) my.getWays().toArray()[0];
722 assertEquals(0, visitor.getConflicts().size());
723 assertEquals("their", merged.getUser().getName());
724 assertEquals(1111, merged.getUser().getId());
725 assertEquals(theirWay.getRawTimestamp(), merged.getRawTimestamp());
726 assertSame(merged, myWay);
727 assertSame(merged.getNode(0), n1);
728 assertSame(merged.getNode(1), n2);
729
730 assertFalse(merged.isModified());
731 }
732
733 /**
734 * My dataset includes a deleted node.
735 * Their dataset includes a way with three nodes, the first one being my node.
736 *
737 * => the merged way should include all three nodes. Deleted node should have deleted=false and
738 * special conflict with isDeleted should exist
739 *
740 */
741 @Test
742 public void wayComplex_mergingADeletedNode() {
743
744 // -- my dataset
745
746 Node mn1 = new Node(LatLon.ZERO);
747 mn1.setOsmId(1, 1);
748 mn1.setDeleted(true);
749 my.addPrimitive(mn1);
750
751 Node tn1 = new Node(LatLon.ZERO);
752 tn1.setOsmId(1, 1);
753 their.addPrimitive(tn1);
754
755 Node tn2 = new Node(new LatLon(1, 1));
756 tn2.setOsmId(2, 1);
757 their.addPrimitive(tn2);
758
759 Node tn3 = new Node(new LatLon(2, 2));
760 tn3.setOsmId(3, 1);
761 their.addPrimitive(tn3);
762
763 // -- their data set
764 Way theirWay = new Way();
765 theirWay.setOsmId(4, 1);
766 theirWay.addNode(tn1);
767 theirWay.addNode(tn2);
768 theirWay.addNode(tn3);
769 theirWay.setUser(User.createOsmUser(1111, "their"));
770 theirWay.setTimestamp(new Date());
771 their.addPrimitive(theirWay);
772
773 DataSetMerger visitor = new DataSetMerger(my, their);
774 visitor.merge();
775
776 assertEquals(1, visitor.getConflicts().size());
777 assertTrue(visitor.getConflicts().get(0).isMyDeleted());
778
779 Way myWay = (Way) my.getPrimitiveById(4, OsmPrimitiveType.WAY);
780 assertEquals(3, myWay.getNodesCount());
781
782 Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
783 assertTrue(myWay.getNodes().contains(n));
784
785 assertFalse(myWay.isModified());
786 }
787
788 /**
789 * My dataset includes a deleted node.
790 * Their dataset includes a relation with three nodes, the first one being my node.
791 *
792 * => the merged relation should include all three nodes. There should be conflict for deleted
793 * node with isMyDeleted set
794 *
795 */
796 @Test
797 public void relationComplex_mergingADeletedNode() {
798
799 Node mn1 = new Node(LatLon.ZERO);
800 mn1.setOsmId(1, 1);
801 mn1.setDeleted(true);
802 my.addPrimitive(mn1);
803
804
805 Node tn1 = new Node(LatLon.ZERO);
806 tn1.setOsmId(1, 1);
807 their.addPrimitive(tn1);
808
809 Node tn2 = new Node(new LatLon(1, 1));
810 tn2.setOsmId(2, 1);
811 their.addPrimitive(tn2);
812
813 Node tn3 = new Node(new LatLon(2, 2));
814 tn3.setOsmId(3, 1);
815 their.addPrimitive(tn3);
816
817
818 Relation theirRelation = new Relation();
819 theirRelation.setOsmId(4, 1);
820
821 theirRelation.addMember(new RelationMember("", tn1));
822 theirRelation.addMember(new RelationMember("", tn2));
823 theirRelation.addMember(new RelationMember("", tn3));
824 their.addPrimitive(theirRelation);
825
826 DataSetMerger visitor = new DataSetMerger(my, their);
827 visitor.merge();
828
829 Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
830 assertNotNull(n);
831
832 assertEquals(1, visitor.getConflicts().size());
833 assertTrue(visitor.getConflicts().hasConflictForMy(n));
834 assertTrue(visitor.getConflicts().get(0).isMyDeleted());
835
836 Relation r = (Relation) my.getPrimitiveById(4, OsmPrimitiveType.RELATION);
837 assertEquals(3, r.getMembersCount());
838
839 assertFalse(r.isModified());
840 }
841
842 /**
843 * Merge an incomplete way with two incomplete nodes into an empty dataset.
844 *
845 * Use case: a way loaded with a multiget, i.e. GET /api/0.6/ways?ids=123456
846 */
847 @Test
848 public void newIncompleteWay() {
849
850 Node n1 = new Node(1);
851 their.addPrimitive(n1);
852
853 Node n2 = new Node(2);
854 their.addPrimitive(n2);
855
856 Way w3 = new Way(3);
857 w3.setNodes(Arrays.asList(n1, n2));
858 their.addPrimitive(w3);
859 assertTrue(w3.isIncomplete());
860
861 DataSetMerger visitor = new DataSetMerger(my, their);
862 visitor.merge();
863
864 assertEquals(0, visitor.getConflicts().size());
865
866 OsmPrimitive p = my.getPrimitiveById(1, OsmPrimitiveType.NODE);
867 assertNotNull(p);
868 assertTrue(p.isIncomplete());
869 p = my.getPrimitiveById(2, OsmPrimitiveType.NODE);
870 assertNotNull(p);
871 assertTrue(p.isIncomplete());
872 p = my.getPrimitiveById(3, OsmPrimitiveType.WAY);
873 assertNotNull(p);
874 assertTrue(p.isIncomplete());
875
876 Way w = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
877 assertNotNull(w);
878 assertTrue(p.isIncomplete());
879 assertEquals(2, w.getNodesCount());
880 assertTrue(w.getNode(0).isIncomplete());
881 assertTrue(w.getNode(1).isIncomplete());
882 }
883
884 /**
885 * Merge an incomplete way with two incomplete nodes into a dataset where the way already exists as complete way.
886 *
887 * Use case: a way loaded with a multiget, i.e. GET /api/0.6/ways?ids=123456 after a "Update selection " of this way
888 */
889 @Test
890 public void incompleteWayOntoCompleteWay() {
891
892 // an incomplete node
893 Node n1 = new Node(1);
894 their.addPrimitive(n1);
895
896 // another incomplete node
897 Node n2 = new Node(2);
898 their.addPrimitive(n2);
899
900 // an incomplete way with two incomplete nodes
901 Way w3 = new Way(3);
902 w3.setNodes(Arrays.asList(n1, n2));
903 their.addPrimitive(w3);
904
905 Node n4 = new Node(LatLon.ZERO);
906 n4.setOsmId(1, 1);
907 my.addPrimitive(n4);
908
909 Node n5 = new Node(new LatLon(1, 1));
910 n5.setOsmId(2, 1);
911 my.addPrimitive(n5);
912
913 Way w6 = new Way(3, 1);
914 w6.setNodes(Arrays.asList(n4, n5));
915 my.addPrimitive(w6);
916
917 DataSetMerger visitor = new DataSetMerger(my, their);
918 visitor.merge();
919
920 assertEquals(0, visitor.getConflicts().size());
921
922 OsmPrimitive p = my.getPrimitiveById(1, OsmPrimitiveType.NODE);
923 assertNotNull(p);
924 assertFalse(p.isIncomplete());
925 p = my.getPrimitiveById(2, OsmPrimitiveType.NODE);
926 assertNotNull(p);
927 assertFalse(p.isIncomplete());
928 p = my.getPrimitiveById(3, OsmPrimitiveType.WAY);
929 assertNotNull(p);
930 assertFalse(p.isIncomplete());
931
932 Way w = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
933 assertNotNull(w);
934 assertFalse(p.isIncomplete());
935 assertEquals(2, w.getNodesCount());
936 assertFalse(w.getNode(0).isIncomplete());
937 assertFalse(w.getNode(1).isIncomplete());
938 }
939
940 /**
941 * merge to complete nodes onto an incomplete way with the same two nodes, but incomplete.
942 * => both the nodes and the way should be complete in the target dataset after merging
943 */
944 @Test
945 public void twoCompleteNodesOntoAnIncompleteWay() {
946
947 // -- source dataset
948
949 // an complete node
950 Node n1 = new Node(1, 1);
951 n1.setCoor(new LatLon(1, 1));
952 their.addPrimitive(n1);
953
954 // another complete node
955 Node n2 = new Node(2, 1);
956 n2.setCoor(new LatLon(2, 2));
957 their.addPrimitive(n2);
958
959 // --- target dataset
960
961 Node n4 = new Node(1);
962 my.addPrimitive(n4);
963
964 Node n5 = new Node(2);
965 my.addPrimitive(n5);
966
967 Way w6 = new Way(3, 1);
968 w6.addNode(n4);
969 w6.addNode(n5);
970 my.addPrimitive(w6);
971
972 //-- merge it
973 DataSetMerger visitor = new DataSetMerger(my, their);
974 visitor.merge();
975
976 // -- test it
977 assertEquals(0, visitor.getConflicts().size());
978
979 Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
980 assertNotNull(n);
981 assertFalse(n.isIncomplete());
982
983 n = (Node) my.getPrimitiveById(2, OsmPrimitiveType.NODE);
984 assertNotNull(n);
985 assertFalse(n.isIncomplete());
986
987 Way w = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
988 assertNotNull(w);
989 assertFalse(w.hasIncompleteNodes());
990 assertTrue(w.isUsable());
991 assertEquals(2, w.getNodesCount());
992 assertEquals(1, w.getNode(0).getId());
993 assertEquals(2, w.getNode(1).getId());
994 }
995
996 /**
997 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/12599">Bug #12599</a>.
998 */
999 @Test
1000 public void testTicket12599() {
1001 // Server node: no modifications
1002 Node n1 = new Node(1, 1);
1003 n1.setCoor(LatLon.ZERO);
1004 assertFalse(n1.isModified());
1005 their.addPrimitive(n1);
1006
1007 // Local node: one modification: addition of an uninteresting tag
1008 Node n1b = new Node(n1);
1009 n1b.setModified(true);
1010 n1b.put("note", "something");
1011 assertTrue(n1b.isModified());
1012 assertEquals(0, n1b.getInterestingTags().size());
1013 my.addPrimitive(n1b);
1014
1015 // Merge
1016 DataSetMerger visitor = new DataSetMerger(my, their);
1017 visitor.merge();
1018
1019 // Check that modification is still here
1020 Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
1021 assertNotNull(n);
1022 assertEquals("something", n.get("note"));
1023 assertTrue(n.isModified());
1024
1025 // Merge again
1026 visitor = new DataSetMerger(my, their);
1027 visitor.merge();
1028
1029 // Check that modification is still here
1030 n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
1031 assertNotNull(n);
1032 assertEquals("something", n.get("note"));
1033 assertTrue(n.isModified());
1034 }
1035
1036
1037 /**
1038 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/12616">Bug #12616</a>.
1039 */
1040 @Test
1041 public void testTicket12616() {
1042 // Server node: no modifications
1043 Node n1 = new Node(1, 1);
1044 n1.setCoor(LatLon.ZERO);
1045 assertFalse(n1.isModified());
1046 their.addPrimitive(n1);
1047
1048 // Local node: one modification: move
1049 Node n1b = new Node(n1);
1050 n1b.setCoor(new LatLon(1, 1));
1051 n1b.setModified(true);
1052 assertTrue(n1b.isModified());
1053 assertEquals(new LatLon(1, 1), n1b.getCoor());
1054 my.addPrimitive(n1b);
1055
1056 // Merge
1057 DataSetMerger visitor = new DataSetMerger(my, their);
1058 visitor.merge();
1059
1060 // Check that modification is still here
1061 Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
1062 assertNotNull(n);
1063 assertEquals(new LatLon(1, 1), n.getCoor());
1064 assertTrue(n.isModified());
1065
1066 // Merge again
1067 visitor = new DataSetMerger(my, their);
1068 visitor.merge();
1069
1070 // Check that modification is still here
1071 n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
1072 assertNotNull(n);
1073 assertEquals(new LatLon(1, 1), n.getCoor());
1074 assertTrue(n.isModified());
1075 }
1076}
Note: See TracBrowser for help on using the repository browser.