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, 8 years ago

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

  • Property svn:eol-style set to native
File size: 31.2 KB
RevLine 
[7937]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;
[8450]7import static org.junit.Assert.assertNotSame;
8import static org.junit.Assert.assertSame;
[7937]9import static org.junit.Assert.assertTrue;
[10378]10import static org.junit.Assert.fail;
[7937]11
12import java.io.StringWriter;
[11035]13import java.time.Instant;
[7937]14import java.util.Arrays;
15import java.util.Date;
16
17import org.junit.After;
18import org.junit.Before;
[10945]19import org.junit.Rule;
[7937]20import org.junit.Test;
21import org.openstreetmap.josm.Main;
22import org.openstreetmap.josm.data.coor.LatLon;
23import org.openstreetmap.josm.data.projection.Projections;
[10945]24import org.openstreetmap.josm.testutils.JOSMTestRules;
[7937]25
[10945]26import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
[8857]27/**
28 * Unit tests for class {@link DataSetMerger}.
29 */
[7937]30public class DataSetMergerTest {
31
[8857]32 /**
33 * Setup test.
34 */
[10945]35 @Rule
36 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
37 public JOSMTestRules test = new JOSMTestRules();
[7937]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
[10378]55 private void runConsistencyTests(DataSet ds) {
[7937]56 StringWriter writer = new StringWriter();
[10378]57 DatasetConsistencyTest test = new DatasetConsistencyTest(ds, writer);
[7937]58 test.checkReferrers();
59 test.checkCompleteWaysWithIncompleteNodes();
60 test.searchNodes();
61 test.searchWays();
62 test.referredPrimitiveNotInDataset();
63 test.checkZeroNodesWays();
64 String result = writer.toString();
[10378]65 if (!result.isEmpty())
66 fail(result);
[7937]67 }
68
69 @After
[10378]70 public void checkDatasets() {
[7937]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
[10758]82 public void testNodeSimpleIdenticalNoConflict() {
[9214]83 Node n = new Node(LatLon.ZERO);
[8510]84 n.setOsmId(1, 1);
[7937]85 n.setModified(false);
86 n.put("key1", "value1");
87 my.addPrimitive(n);
88
[9214]89 Node n1 = new Node(LatLon.ZERO);
[8510]90 n1.setOsmId(1, 1);
[7937]91 n1.setModified(false);
92 n1.put("key1", "value1");
93 their.addPrimitive(n1);
94
95
[8510]96 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]97 visitor.merge();
98
[8510]99 Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
[7937]100 assertTrue(visitor.getConflicts().isEmpty());
[8450]101 assertNotSame(n1, n2); // make sure we have a clone
[7937]102 assertEquals(1, n2.getId());
103 assertEquals(1, n2.getVersion());
[8450]104 assertFalse(n2.isModified());
[7937]105 assertEquals("value1", n2.get("key1"));
106
107 // merge target not modified after merging
[8450]108 assertFalse(n2.isModified());
[7937]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
[10758]116 public void testNodeSimpleLocallyUnmodifiedNoConflict() {
[9214]117 Node n = new Node(LatLon.ZERO);
[8510]118 n.setOsmId(1, 1);
[7937]119 n.setModified(false);
120 n.put("key1", "value1");
121 my.addPrimitive(n);
122
[9214]123 Node n1 = new Node(LatLon.ZERO);
[8510]124 n1.setOsmId(1, 2);
[7937]125 n1.setModified(false);
126 n1.put("key1", "value1-new");
127 n1.put("key2", "value2");
128 their.addPrimitive(n1);
129
130
[8510]131 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]132 visitor.merge();
133
[8510]134 Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
[7937]135 assertTrue(visitor.getConflicts().isEmpty());
[8450]136 assertSame(n, n2); // make sure the merged node is still the original node
137 assertSame(n2.getDataSet(), my);
[7937]138 assertEquals(1, n2.getId());
139 assertEquals(2, n2.getVersion());
[8450]140 assertFalse(n2.isModified());
[7937]141 assertEquals("value1-new", n2.get("key1"));
142 assertEquals("value2", n2.get("key2"));
143
144 // the merge target should not be modified
[8450]145 assertFalse(n2.isModified());
[7937]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
[10758]156 public void testNodeSimpleTagConflict() {
[9214]157 Node n = new Node(LatLon.ZERO);
[8510]158 n.setOsmId(1, 1);
[7937]159 n.setModified(true);
160 n.put("key1", "value1");
161 n.put("key2", "value2");
162 my.addPrimitive(n);
163
[9214]164 Node n1 = new Node(LatLon.ZERO);
[8510]165 n1.setOsmId(1, 2);
[7937]166 n1.setModified(false);
167 n1.put("key1", "value1-new");
168
169 their.addPrimitive(n1);
170
171
[8510]172 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]173 visitor.merge();
174
[8510]175 Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
176 assertEquals(1, visitor.getConflicts().size());
[8450]177 assertSame(n, n2);
178 assertNotSame(n1, n2);
179 assertSame(n1.getDataSet(), their);
[7937]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
[10758]190 public void testNodeSimpleDeleteConflict() {
[7937]191 Node n = new Node(1, 1);
[9214]192 n.setCoor(LatLon.ZERO);
[7937]193 n.setDeleted(true);
194 n.put("key1", "value1");
195 my.addPrimitive(n);
196
[9214]197 Node n1 = new Node(LatLon.ZERO);
[8510]198 n1.setOsmId(1, 2);
[7937]199 n1.setModified(false);
200 n1.put("key1", "value1-new");
201 n1.put("key2", "value2");
202 their.addPrimitive(n1);
203
204
[8510]205 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]206 visitor.merge();
207
[8510]208 Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
209 assertEquals(1, visitor.getConflicts().size());
[8450]210 assertSame(n, n2);
211 assertNotSame(n1, n2);
212 assertSame(n1.getDataSet(), their);
[7937]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
[10758]220 public void testNodeSimpleDeleteConflict2() {
[9214]221 Node n = new Node(LatLon.ZERO);
[8510]222 n.setOsmId(1, 1);
[7937]223 n.setDeleted(true);
224 my.addPrimitive(n);
225
[9214]226 Node n1 = new Node(LatLon.ZERO);
[8510]227 n1.setOsmId(1, 1);
[7937]228 their.addPrimitive(n1);
229
230
[8510]231 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]232 visitor.merge();
233
[8510]234 Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
235 assertEquals(0, visitor.getConflicts().size());
[8450]236 assertTrue(n2.isVisible());
237 assertSame(n, n2);
238 assertSame(n.getDataSet(), my);
239 assertSame(n1.getDataSet(), their);
[7937]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
[10758]248 public void testNodeSimpleDeleteConflict3() {
[8510]249 Node n = new Node(new LatLon(1, 1));
[7937]250 n.setDeleted(true);
251 my.addPrimitive(n);
252
[8510]253 Node n1 = new Node(new LatLon(1, 1));
[7937]254 their.addPrimitive(n1);
255
256
[8510]257 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]258 visitor.merge();
259
260 assertEquals(0, visitor.getConflicts().size());
[8450]261 assertSame(n.getDataSet(), my);
262 assertSame(n1.getDataSet(), their);
[7937]263 }
264
265 /**
266 * My and their node are new but semantically equal. Both are deleted.
267 *
268 * => take mine
269 */
270 @Test
[10758]271 public void testNodeSimpleDeleteConflict4() {
[8510]272 Node n = new Node(new LatLon(1, 1));
[7937]273 n.setDeleted(true);
274 my.addPrimitive(n);
275
[8510]276 Node n1 = new Node(new LatLon(1, 1));
[7937]277 n1.setDeleted(true);
278 their.addPrimitive(n1);
279
[8510]280 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]281 visitor.merge();
282
[8510]283 assertEquals(0, visitor.getConflicts().size());
284 Node n2 = (Node) my.getNodes().toArray()[0];
[8450]285 assertSame(n2, n);
[7937]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
[10758]296 public void testNodeSimpleNoIdSemanticallyEqual() {
[7937]297
298 User myUser = User.createOsmUser(1111, "my");
299
300 User theirUser = User.createOsmUser(222, "their");
301
302 Node n = new Node();
[9214]303 n.setCoor(LatLon.ZERO);
[7937]304 n.put("key1", "value1");
305 n.setUser(myUser);
[11035]306 n.setTimestamp(new Date());
[7937]307
308 my.addPrimitive(n);
309
310 Node n1 = new Node();
[9214]311 n1.setCoor(LatLon.ZERO);
[7937]312 n1.put("key1", "value1");
[11035]313 n1.setTimestamp(Date.from(Instant.now().plusSeconds(3600)));
[7937]314 n1.setUser(theirUser);
315 their.addPrimitive(n1);
316
[8510]317 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]318 visitor.merge();
319
320 Node n2 = my.getNodes().iterator().next();
[8510]321 assertEquals(0, visitor.getConflicts().size());
322 assertEquals("value1", n2.get("key1"));
[8565]323 assertEquals(n1.getRawTimestamp(), n2.getRawTimestamp());
[8510]324 assertEquals(theirUser, n2.getUser());
[8450]325 assertSame(n2, n);
326 assertNotSame(n2, n1);
327 assertSame(n2.getDataSet(), my);
[7937]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
[10758]336 public void testNodeSimpleIncompleteNode() {
[7937]337
338 Node n = new Node(1);
339 my.addPrimitive(n);
340
341 Node n1 = new Node();
[9214]342 n1.setCoor(LatLon.ZERO);
[8510]343 n1.setOsmId(1, 1);
[7937]344 n1.put("key1", "value1");
345 Date timestamp = new Date();
346 n1.setTimestamp(timestamp);
347 their.addPrimitive(n1);
348
[8510]349 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]350 visitor.merge();
351
352 Node n2 = my.getNodes().iterator().next();
[8510]353 assertEquals(0, visitor.getConflicts().size());
354 assertEquals("value1", n2.get("key1"));
[8565]355 assertEquals(n1.getRawTimestamp(), n2.getRawTimestamp());
[8450]356 assertFalse(n2.isIncomplete());
357 assertSame(n2, n);
[7937]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
[10758]367 public void testWaySimpleIdenticalNodesDifferentTags() {
[7937]368
369 // -- the target dataset
370
371 Node n1 = new Node();
[9214]372 n1.setCoor(LatLon.ZERO);
[8510]373 n1.setOsmId(1, 1);
[7937]374 my.addPrimitive(n1);
375
376 Node n2 = new Node();
[9214]377 n2.setCoor(LatLon.ZERO);
[8510]378 n2.setOsmId(2, 1);
[7937]379
380 my.addPrimitive(n2);
381
382 Way myWay = new Way();
[8510]383 myWay.setOsmId(3, 1);
[7937]384 myWay.put("key1", "value1");
385 myWay.addNode(n1);
386 myWay.addNode(n2);
387 my.addPrimitive(myWay);
388
389 // -- the source data set
390
[9214]391 Node n3 = new Node(LatLon.ZERO);
[8510]392 n3.setOsmId(1, 1);
[7937]393 their.addPrimitive(n3);
394
[8510]395 Node n4 = new Node(new LatLon(1, 1));
396 n4.setOsmId(2, 1);
[7937]397 their.addPrimitive(n4);
398
399 Way theirWay = new Way();
[8510]400 theirWay.setOsmId(3, 2);
[7937]401 theirWay.put("key1", "value1");
402 theirWay.put("key2", "value2");
403 theirWay.addNode(n3);
404 theirWay.addNode(n4);
405 their.addPrimitive(theirWay);
406
407
[8510]408 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]409 visitor.merge();
410
411 // -- tests
[8510]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());
[8450]421 assertSame(merged, myWay);
422 assertSame(merged.getDataSet(), my);
[7937]423
[8510]424 Node mergedNode = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
[8450]425 assertSame(mergedNode, n1);
[8510]426 mergedNode = (Node) my.getPrimitiveById(2, OsmPrimitiveType.NODE);
[8450]427 assertSame(mergedNode, n2);
[7937]428
[8450]429 assertFalse(merged.isModified());
[7937]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
[10758]439 public void testWaySimpleAdditionalNodesAndChangedNodes() {
[7937]440
441 // -- my data set
442
[9214]443 Node n1 = new Node(LatLon.ZERO);
[8510]444 n1.setOsmId(1, 1);
[7937]445 my.addPrimitive(n1);
446
[8510]447 Node n2 = new Node(new LatLon(1, 1));
448 n2.setOsmId(2, 1);
[7937]449 my.addPrimitive(n2);
450
451 Way myWay = new Way();
[8510]452 myWay.setOsmId(3, 1);
[7937]453 myWay.addNode(n1);
454 myWay.addNode(n2);
455 my.addPrimitive(myWay);
456
457 // --- their data set
458
[9214]459 Node n3 = new Node(LatLon.ZERO);
[8510]460 n3.setOsmId(1, 1);
[7937]461 their.addPrimitive(n3);
462
[8510]463 Node n5 = new Node(new LatLon(1, 1));
464 n5.setOsmId(4, 1);
[7937]465
466 their.addPrimitive(n5);
467
[8510]468 Node n4 = new Node(new LatLon(2, 2));
469 n4.setOsmId(2, 2);
[7937]470 n4.put("key1", "value1");
471 their.addPrimitive(n4);
472
473
474 Way theirWay = new Way();
[8510]475 theirWay.setOsmId(3, 2);
[7937]476 theirWay.addNode(n3);
477 theirWay.addNode(n5); // insert a node
478 theirWay.addNode(n4); // this one is updated
479 their.addPrimitive(theirWay);
480
[8510]481 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]482 visitor.merge();
483
484 // -- tests
[8510]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"));
[7937]494
[8450]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);
[7937]498
[8450]499 assertFalse(merged.isModified()); // the target wasn't modified before merging, it mustn't be after merging
[7937]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
[10758]508 public void testWaySimpleDifferentNodesAndMyIsModified() {
[7937]509
510 // -- the target dataset
511
[9214]512 Node n1 = new Node(LatLon.ZERO);
[8510]513 n1.setOsmId(1, 1);
[7937]514 my.addPrimitive(n1);
515
[8510]516 Node n2 = new Node(new LatLon(1, 1));
517 n2.setOsmId(2, 1);
[7937]518 my.addPrimitive(n2);
519
520 Way myWay = new Way();
[8510]521 myWay.setOsmId(3, 1);
[7937]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
[9214]531 Node n3 = new Node(LatLon.ZERO);
[8510]532 n3.setOsmId(1, 1);
[7937]533 their.addPrimitive(n3);
534
[8510]535 Node n5 = new Node(new LatLon(1, 1));
536 n5.setOsmId(4, 1);
[7937]537 their.addPrimitive(n5);
538
[8510]539 Node n4 = new Node(new LatLon(2, 2));
540 n4.setOsmId(2, 1);
[7937]541 n4.put("key1", "value1");
542 their.addPrimitive(n4);
543
544 Way theirWay = new Way();
[8510]545 theirWay.setOsmId(3, 2);
[7937]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
[8510]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"));
[7937]564 }
565
566 /**
567 * their way is not visible anymore.
568 *
569 * => conflict
570 */
571 @Test
[10758]572 public void testWaySimpleTheirVersionNotVisibleMyIsModified() {
[7937]573
[9214]574 Node mn1 = new Node(LatLon.ZERO);
[8510]575 mn1.setOsmId(1, 1);
[7937]576 my.addPrimitive(mn1);
577
[8510]578 Node mn2 = new Node(new LatLon(1, 1));
579 mn2.setOsmId(2, 1);
[7937]580 my.addPrimitive(mn2);
581
582 Way myWay = new Way();
[8510]583 myWay.setOsmId(3, 1);
[7937]584 myWay.addNode(mn1);
585 myWay.addNode(mn2);
586 myWay.setModified(true);
587 my.addPrimitive(myWay);
588
589 Way theirWay = new Way();
[8510]590 theirWay.setOsmId(3, 2);
[7937]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
[8510]598 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]599 visitor.merge();
600
[8510]601 Way merged = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
602 assertEquals(1, visitor.getConflicts().size());
[8450]603 assertTrue(visitor.getConflicts().hasConflictForMy(myWay));
604 assertTrue(visitor.getConflicts().hasConflictForTheir(theirWay));
[8510]605 assertEquals(myWay, merged);
[7937]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
[10758]614 public void testWaySimpleTwoWaysWithNoIdNodesWithId() {
[7937]615
616 // -- my data set
617
[9214]618 Node n1 = new Node(LatLon.ZERO);
[8510]619 n1.setOsmId(1, 1);
[7937]620 my.addPrimitive(n1);
621
[8510]622 Node n2 = new Node(new LatLon(1, 1));
623 n2.setOsmId(2, 1);
[7937]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
[9214]633 Node n3 = new Node(LatLon.ZERO);
[8510]634 n3.setOsmId(1, 1);
[7937]635 their.addPrimitive(n3);
636
[8510]637 Node n4 = new Node(new LatLon(1, 1));
638 n4.setOsmId(2, 1);
[7937]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
[8510]649 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]650 visitor.merge();
651
652 // -- tests
[8510]653 Way merged = (Way) my.getWays().toArray()[0];
654 assertEquals(0, visitor.getConflicts().size());
[7937]655 assertEquals("their", merged.getUser().getName());
656 assertEquals(1111, merged.getUser().getId());
[8565]657 assertEquals(theirWay.getRawTimestamp(), merged.getRawTimestamp());
[8450]658 assertSame(merged, myWay);
659 assertSame(merged.getNode(0), n1);
660 assertSame(merged.getNode(1), n2);
[7937]661
[8450]662 assertFalse(merged.isModified());
[7937]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
[10758]671 public void testWaySimpleTwoWaysWithNoIdNodesWithoutId() {
[7937]672
673 // -- my data set
674
[9214]675 Node n1 = new Node(LatLon.ZERO);
[7937]676 my.addPrimitive(n1);
677
[8510]678 Node n2 = new Node(new LatLon(1, 1));
[7937]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
[9214]688 Node n3 = new Node(LatLon.ZERO);
[7937]689 their.addPrimitive(n3);
690
[8510]691 Node n4 = new Node(new LatLon(1, 1));
[7937]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
[8510]702 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]703 visitor.merge();
704
705 // -- tests
[8510]706 Way merged = (Way) my.getWays().toArray()[0];
707 assertEquals(0, visitor.getConflicts().size());
[7937]708 assertEquals("their", merged.getUser().getName());
709 assertEquals(1111, merged.getUser().getId());
[8565]710 assertEquals(theirWay.getRawTimestamp(), merged.getRawTimestamp());
[8450]711 assertSame(merged, myWay);
712 assertSame(merged.getNode(0), n1);
713 assertSame(merged.getNode(1), n2);
[7937]714
[8450]715 assertFalse(merged.isModified());
[7937]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
[10758]726 public void testWayComplexMergingADeletedNode() {
[7937]727
728 // -- my dataset
729
[9214]730 Node mn1 = new Node(LatLon.ZERO);
[8510]731 mn1.setOsmId(1, 1);
[7937]732 mn1.setDeleted(true);
733 my.addPrimitive(mn1);
734
[9214]735 Node tn1 = new Node(LatLon.ZERO);
[8510]736 tn1.setOsmId(1, 1);
[7937]737 their.addPrimitive(tn1);
738
[8510]739 Node tn2 = new Node(new LatLon(1, 1));
740 tn2.setOsmId(2, 1);
[7937]741 their.addPrimitive(tn2);
742
[8510]743 Node tn3 = new Node(new LatLon(2, 2));
744 tn3.setOsmId(3, 1);
[7937]745 their.addPrimitive(tn3);
746
747 // -- their data set
748 Way theirWay = new Way();
[8510]749 theirWay.setOsmId(4, 1);
[7937]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
[8510]757 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]758 visitor.merge();
759
760 assertEquals(1, visitor.getConflicts().size());
761 assertTrue(visitor.getConflicts().get(0).isMyDeleted());
762
[8510]763 Way myWay = (Way) my.getPrimitiveById(4, OsmPrimitiveType.WAY);
[7937]764 assertEquals(3, myWay.getNodesCount());
765
[8510]766 Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
[7937]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
[10758]780 public void testRelationComplexMergingADeletedNode() {
[7937]781
[9214]782 Node mn1 = new Node(LatLon.ZERO);
[8510]783 mn1.setOsmId(1, 1);
[7937]784 mn1.setDeleted(true);
785 my.addPrimitive(mn1);
786
[9214]787 Node tn1 = new Node(LatLon.ZERO);
[8510]788 tn1.setOsmId(1, 1);
[7937]789 their.addPrimitive(tn1);
790
[8510]791 Node tn2 = new Node(new LatLon(1, 1));
792 tn2.setOsmId(2, 1);
[7937]793 their.addPrimitive(tn2);
794
[8510]795 Node tn3 = new Node(new LatLon(2, 2));
796 tn3.setOsmId(3, 1);
[7937]797 their.addPrimitive(tn3);
798
799 Relation theirRelation = new Relation();
[8510]800 theirRelation.setOsmId(4, 1);
[7937]801
802 theirRelation.addMember(new RelationMember("", tn1));
803 theirRelation.addMember(new RelationMember("", tn2));
804 theirRelation.addMember(new RelationMember("", tn3));
805 their.addPrimitive(theirRelation);
806
[8510]807 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]808 visitor.merge();
809
[8510]810 Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
[8450]811 assertNotNull(n);
[7937]812
813 assertEquals(1, visitor.getConflicts().size());
814 assertTrue(visitor.getConflicts().hasConflictForMy(n));
815 assertTrue(visitor.getConflicts().get(0).isMyDeleted());
816
[8510]817 Relation r = (Relation) my.getPrimitiveById(4, OsmPrimitiveType.RELATION);
[7937]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
[10758]829 public void testNewIncompleteWay() {
[7937]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);
[8510]838 w3.setNodes(Arrays.asList(n1, n2));
[7937]839 their.addPrimitive(w3);
840 assertTrue(w3.isIncomplete());
841
842 DataSetMerger visitor = new DataSetMerger(my, their);
843 visitor.merge();
844
[8510]845 assertEquals(0, visitor.getConflicts().size());
[7937]846
[8510]847 OsmPrimitive p = my.getPrimitiveById(1, OsmPrimitiveType.NODE);
[7937]848 assertNotNull(p);
849 assertTrue(p.isIncomplete());
[8510]850 p = my.getPrimitiveById(2, OsmPrimitiveType.NODE);
[7937]851 assertNotNull(p);
852 assertTrue(p.isIncomplete());
[8510]853 p = my.getPrimitiveById(3, OsmPrimitiveType.WAY);
[7937]854 assertNotNull(p);
855 assertTrue(p.isIncomplete());
856
[8510]857 Way w = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
[7937]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
[10758]871 public void testIncompleteWayOntoCompleteWay() {
[7937]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);
[8510]883 w3.setNodes(Arrays.asList(n1, n2));
[7937]884 their.addPrimitive(w3);
885
[9214]886 Node n4 = new Node(LatLon.ZERO);
[8510]887 n4.setOsmId(1, 1);
[7937]888 my.addPrimitive(n4);
889
[8510]890 Node n5 = new Node(new LatLon(1, 1));
891 n5.setOsmId(2, 1);
[7937]892 my.addPrimitive(n5);
893
894 Way w6 = new Way(3, 1);
[8510]895 w6.setNodes(Arrays.asList(n4, n5));
[7937]896 my.addPrimitive(w6);
897
[8510]898 DataSetMerger visitor = new DataSetMerger(my, their);
[7937]899 visitor.merge();
900
[8510]901 assertEquals(0, visitor.getConflicts().size());
[7937]902
[8510]903 OsmPrimitive p = my.getPrimitiveById(1, OsmPrimitiveType.NODE);
[7937]904 assertNotNull(p);
[8450]905 assertFalse(p.isIncomplete());
[8510]906 p = my.getPrimitiveById(2, OsmPrimitiveType.NODE);
[7937]907 assertNotNull(p);
[8450]908 assertFalse(p.isIncomplete());
[8510]909 p = my.getPrimitiveById(3, OsmPrimitiveType.WAY);
[7937]910 assertNotNull(p);
[8450]911 assertFalse(p.isIncomplete());
[7937]912
[8510]913 Way w = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
[7937]914 assertNotNull(w);
[8450]915 assertFalse(p.isIncomplete());
[7937]916 assertEquals(2, w.getNodesCount());
[8450]917 assertFalse(w.getNode(0).isIncomplete());
918 assertFalse(w.getNode(1).isIncomplete());
[7937]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
[10758]926 public void testTwoCompleteNodesOntoAnIncompleteWay() {
[7937]927
928 // -- source dataset
929
930 // an complete node
931 Node n1 = new Node(1, 1);
[8510]932 n1.setCoor(new LatLon(1, 1));
[7937]933 their.addPrimitive(n1);
934
935 // another complete node
936 Node n2 = new Node(2, 1);
[8510]937 n2.setCoor(new LatLon(2, 2));
[7937]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
[8510]958 assertEquals(0, visitor.getConflicts().size());
[7937]959
[8510]960 Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
[7937]961 assertNotNull(n);
962 assertFalse(n.isIncomplete());
963
[8510]964 n = (Node) my.getPrimitiveById(2, OsmPrimitiveType.NODE);
[7937]965 assertNotNull(n);
966 assertFalse(n.isIncomplete());
967
[8510]968 Way w = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
[7937]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 }
[9961]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
[9979]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 }
[7937]1057}
Note: See TracBrowser for help on using the repository browser.