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

Last change on this file since 3034 was 3034, checked in by jttt, 14 years ago

Fix #4467 Don't silently drop locally deleted member primitives from downloaded ways and relation (fix the issue when deleted primitive is referenced)

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