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

Last change on this file since 11035 was 11035, checked in by simon04, 2 years ago

see #13376 - Replace Calendar usages with Java 8 Date API

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