/**
   * Node with same id, my is modified, their has a higher version => results in a conflict
   *
   * <p>Use case: node which is modified locally and updated by another mapper on the server
   */
  @Test
  public void nodeSimple_TagConflict() {
    Node n = new Node(new LatLon(0, 0));
    n.setOsmId(1, 1);
    n.setModified(true);
    n.put("key1", "value1");
    n.put("key2", "value2");
    my.addPrimitive(n);

    Node n1 = new Node(new LatLon(0, 0));
    n1.setOsmId(1, 2);
    n1.setModified(false);
    n1.put("key1", "value1-new");

    their.addPrimitive(n1);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
    assertEquals(1, visitor.getConflicts().size());
    assertSame(n, n2);
    assertNotSame(n1, n2);
    assertSame(n1.getDataSet(), their);
  }
  /**
   * two identical nodes, even in id and version. No confict expected.
   *
   * <p>Can happen if data is loaded in two layers and then merged from one layer on the other.
   */
  @Test
  public void nodeSimple_IdenticalNoConflict() {
    Node n = new Node(new LatLon(0, 0));
    n.setOsmId(1, 1);
    n.setModified(false);
    n.put("key1", "value1");
    my.addPrimitive(n);

    Node n1 = new Node(new LatLon(0, 0));
    n1.setOsmId(1, 1);
    n1.setModified(false);
    n1.put("key1", "value1");
    their.addPrimitive(n1);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
    assertTrue(visitor.getConflicts().isEmpty());
    assertNotSame(n1, n2); // make sure we have a clone
    assertEquals(1, n2.getId());
    assertEquals(1, n2.getVersion());
    assertFalse(n2.isModified());
    assertEquals("value1", n2.get("key1"));

    // merge target not modified after merging
    assertFalse(n2.isModified());
  }
  /**
   * two nodes, my is unmodified, their is updated and has a higher version => their version is
   * going to be the merged version
   */
  @Test
  public void nodeSimple_locallyUnmodifiedNoConflict() {
    Node n = new Node(new LatLon(0, 0));
    n.setOsmId(1, 1);
    n.setModified(false);
    n.put("key1", "value1");
    my.addPrimitive(n);

    Node n1 = new Node(new LatLon(0, 0));
    n1.setOsmId(1, 2);
    n1.setModified(false);
    n1.put("key1", "value1-new");
    n1.put("key2", "value2");
    their.addPrimitive(n1);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
    assertTrue(visitor.getConflicts().isEmpty());
    assertSame(n, n2); // make sure the merged node is still the original node
    assertSame(n2.getDataSet(), my);
    assertEquals(1, n2.getId());
    assertEquals(2, n2.getVersion());
    assertFalse(n2.isModified());
    assertEquals("value1-new", n2.get("key1"));
    assertEquals("value2", n2.get("key2"));

    // the merge target should not be modified
    assertFalse(n2.isModified());
  }
  /**
   * their way has a higher version and different nodes. My way is modified.
   *
   * <p>=> merge onto my way not possible, create a conflict
   */
  @Test
  public void waySimple_DifferentNodesAndMyIsModified() {

    // -- the target dataset

    Node n1 = new Node(new LatLon(0, 0));
    n1.setOsmId(1, 1);
    my.addPrimitive(n1);

    Node n2 = new Node(new LatLon(1, 1));
    n2.setOsmId(2, 1);
    my.addPrimitive(n2);

    Way myWay = new Way();
    myWay.setOsmId(3, 1);

    myWay.addNode(n1);
    myWay.addNode(n2);
    myWay.setModified(true);
    myWay.put("key1", "value1");
    my.addPrimitive(myWay);

    // -- the source dataset

    Node n3 = new Node(new LatLon(0, 0));
    n3.setOsmId(1, 1);
    their.addPrimitive(n3);

    Node n5 = new Node(new LatLon(1, 1));
    n5.setOsmId(4, 1);
    their.addPrimitive(n5);

    Node n4 = new Node(new LatLon(2, 2));
    n4.setOsmId(2, 1);
    n4.put("key1", "value1");
    their.addPrimitive(n4);

    Way theirWay = new Way();
    theirWay.setOsmId(3, 2);

    theirWay.addNode(n3);
    theirWay.addNode(n5); // insert a node
    theirWay.addNode(n4); // this one is updated
    their.addPrimitive(theirWay);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    Way merged = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
    assertEquals(1, visitor.getConflicts().size());
    assertEquals(3, merged.getId());
    assertEquals(1, merged.getVersion());
    assertEquals(2, merged.getNodesCount());
    assertEquals(1, merged.getNode(0).getId());
    assertEquals(2, merged.getNode(1).getId());
    assertEquals("value1", merged.get("key1"));
  }
  /**
   * merge to complete nodes onto an incomplete way with the same two nodes, but incomplete. => both
   * the nodes and the way should be complete in the target dataset after merging
   */
  @Test
  public void twoCompleteNodesOntoAnIncompleteWay() {

    // -- source dataset

    // an complete node
    Node n1 = new Node(1, 1);
    n1.setCoor(new LatLon(1, 1));
    their.addPrimitive(n1);

    // another complete node
    Node n2 = new Node(2, 1);
    n2.setCoor(new LatLon(2, 2));
    their.addPrimitive(n2);

    // --- target dataset

    Node n4 = new Node(1);
    my.addPrimitive(n4);

    Node n5 = new Node(2);
    my.addPrimitive(n5);

    Way w6 = new Way(3, 1);
    w6.addNode(n4);
    w6.addNode(n5);
    my.addPrimitive(w6);

    // -- merge it
    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    // -- test it
    assertEquals(0, visitor.getConflicts().size());

    Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
    assertNotNull(n);
    assertFalse(n.isIncomplete());

    n = (Node) my.getPrimitiveById(2, OsmPrimitiveType.NODE);
    assertNotNull(n);
    assertFalse(n.isIncomplete());

    Way w = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
    assertNotNull(w);
    assertFalse(w.hasIncompleteNodes());
    assertTrue(w.isUsable());
    assertEquals(2, w.getNodesCount());
    assertEquals(1, w.getNode(0).getId());
    assertEquals(2, w.getNode(1).getId());
  }
  /**
   * my and their way have no ids, nodes they refer to have an id. but my and their way are
   * semantically equal. so technical attributes of their way can be merged on my way. No conflict.
   */
  @Test
  public void waySimple_twoWaysWithNoId_NodesWithId() {

    // -- my data set

    Node n1 = new Node(new LatLon(0, 0));
    n1.setOsmId(1, 1);
    my.addPrimitive(n1);

    Node n2 = new Node(new LatLon(1, 1));
    n2.setOsmId(2, 1);
    my.addPrimitive(n2);

    Way myWay = new Way();
    myWay.addNode(n1);
    myWay.addNode(n2);
    my.addPrimitive(myWay);

    // -- their data set

    Node n3 = new Node(new LatLon(0, 0));
    n3.setOsmId(1, 1);
    their.addPrimitive(n3);

    Node n4 = new Node(new LatLon(1, 1));
    n4.setOsmId(2, 1);
    their.addPrimitive(n4);

    Way theirWay = new Way();
    theirWay.addNode(n3);
    theirWay.addNode(n4);
    User user = User.createOsmUser(1111, "their");
    theirWay.setUser(user);
    theirWay.setTimestamp(new Date());
    their.addPrimitive(theirWay);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    // -- tests
    Way merged = (Way) my.getWays().toArray()[0];
    assertEquals(0, visitor.getConflicts().size());
    assertEquals("their", merged.getUser().getName());
    assertEquals(1111, merged.getUser().getId());
    assertEquals(theirWay.getRawTimestamp(), merged.getRawTimestamp());
    assertSame(merged, myWay);
    assertSame(merged.getNode(0), n1);
    assertSame(merged.getNode(1), n2);

    assertFalse(merged.isModified());
  }
  /**
   * Merge an incomplete way with two incomplete nodes into a dataset where the way already exists
   * as complete way.
   *
   * <p>Use case: a way loaded with a multiget, i.e. GET /api/0.6/ways?ids=123456 after a "Update
   * selection " of this way
   */
  @Test
  public void incompleteWayOntoCompleteWay() {

    // an incomplete node
    Node n1 = new Node(1);
    their.addPrimitive(n1);

    // another incomplete node
    Node n2 = new Node(2);
    their.addPrimitive(n2);

    // an incomplete way with two incomplete nodes
    Way w3 = new Way(3);
    w3.setNodes(Arrays.asList(n1, n2));
    their.addPrimitive(w3);

    Node n4 = new Node(new LatLon(0, 0));
    n4.setOsmId(1, 1);
    my.addPrimitive(n4);

    Node n5 = new Node(new LatLon(1, 1));
    n5.setOsmId(2, 1);
    my.addPrimitive(n5);

    Way w6 = new Way(3, 1);
    w6.setNodes(Arrays.asList(n4, n5));
    my.addPrimitive(w6);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    assertEquals(0, visitor.getConflicts().size());

    OsmPrimitive p = my.getPrimitiveById(1, OsmPrimitiveType.NODE);
    assertNotNull(p);
    assertFalse(p.isIncomplete());
    p = my.getPrimitiveById(2, OsmPrimitiveType.NODE);
    assertNotNull(p);
    assertFalse(p.isIncomplete());
    p = my.getPrimitiveById(3, OsmPrimitiveType.WAY);
    assertNotNull(p);
    assertFalse(p.isIncomplete());

    Way w = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
    assertNotNull(w);
    assertFalse(p.isIncomplete());
    assertEquals(2, w.getNodesCount());
    assertFalse(w.getNode(0).isIncomplete());
    assertFalse(w.getNode(1).isIncomplete());
  }
  /**
   * My and their node are new but semantically equal. My node is deleted.
   *
   * <p>=> Ignore my node, no conflict
   */
  @Test
  public void nodeSimple_DeleteConflict_3() {
    Node n = new Node(new LatLon(1, 1));
    n.setDeleted(true);
    my.addPrimitive(n);

    Node n1 = new Node(new LatLon(1, 1));
    their.addPrimitive(n1);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    assertEquals(0, visitor.getConflicts().size());
    assertSame(n.getDataSet(), my);
    assertSame(n1.getDataSet(), their);
  }
  /**
   * My dataset includes a deleted node. Their dataset includes a way with three nodes, the first
   * one being my node.
   *
   * <p>=> the merged way should include all three nodes. Deleted node should have deleted=false and
   * special conflict with isDeleted should exist
   */
  @Test
  public void wayComplex_mergingADeletedNode() {

    // -- my dataset

    Node mn1 = new Node(new LatLon(0, 0));
    mn1.setOsmId(1, 1);
    mn1.setDeleted(true);
    my.addPrimitive(mn1);

    Node tn1 = new Node(new LatLon(0, 0));
    tn1.setOsmId(1, 1);
    their.addPrimitive(tn1);

    Node tn2 = new Node(new LatLon(1, 1));
    tn2.setOsmId(2, 1);
    their.addPrimitive(tn2);

    Node tn3 = new Node(new LatLon(2, 2));
    tn3.setOsmId(3, 1);
    their.addPrimitive(tn3);

    // -- their data set
    Way theirWay = new Way();
    theirWay.setOsmId(4, 1);
    theirWay.addNode(tn1);
    theirWay.addNode(tn2);
    theirWay.addNode(tn3);
    theirWay.setUser(User.createOsmUser(1111, "their"));
    theirWay.setTimestamp(new Date());
    their.addPrimitive(theirWay);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    assertEquals(1, visitor.getConflicts().size());
    assertTrue(visitor.getConflicts().get(0).isMyDeleted());

    Way myWay = (Way) my.getPrimitiveById(4, OsmPrimitiveType.WAY);
    assertEquals(3, myWay.getNodesCount());

    Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
    assertTrue(myWay.getNodes().contains(n));

    assertFalse(myWay.isModified());
  }
  /**
   * My and their node are new but semantically equal. Both are deleted.
   *
   * <p>=> take mine
   */
  @Test
  public void nodeSimple_DeleteConflict_4() {
    Node n = new Node(new LatLon(1, 1));
    n.setDeleted(true);
    my.addPrimitive(n);

    Node n1 = new Node(new LatLon(1, 1));
    n1.setDeleted(true);
    their.addPrimitive(n1);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    assertEquals(0, visitor.getConflicts().size());
    Node n2 = (Node) my.getNodes().toArray()[0];
    assertSame(n2, n);
    assertTrue(n2.isDeleted());
  }
  /**
   * My dataset includes a deleted node. Their dataset includes a relation with three nodes, the
   * first one being my node.
   *
   * <p>=> the merged relation should include all three nodes. There should be conflict for deleted
   * node with isMyDeleted set
   */
  @Test
  public void relationComplex_mergingADeletedNode() {

    Node mn1 = new Node(new LatLon(0, 0));
    mn1.setOsmId(1, 1);
    mn1.setDeleted(true);
    my.addPrimitive(mn1);

    Node tn1 = new Node(new LatLon(0, 0));
    tn1.setOsmId(1, 1);
    their.addPrimitive(tn1);

    Node tn2 = new Node(new LatLon(1, 1));
    tn2.setOsmId(2, 1);
    their.addPrimitive(tn2);

    Node tn3 = new Node(new LatLon(2, 2));
    tn3.setOsmId(3, 1);
    their.addPrimitive(tn3);

    Relation theirRelation = new Relation();
    theirRelation.setOsmId(4, 1);

    theirRelation.addMember(new RelationMember("", tn1));
    theirRelation.addMember(new RelationMember("", tn2));
    theirRelation.addMember(new RelationMember("", tn3));
    their.addPrimitive(theirRelation);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    Node n = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
    assertNotNull(n);

    assertEquals(1, visitor.getConflicts().size());
    assertTrue(visitor.getConflicts().hasConflictForMy(n));
    assertTrue(visitor.getConflicts().get(0).isMyDeleted());

    Relation r = (Relation) my.getPrimitiveById(4, OsmPrimitiveType.RELATION);
    assertEquals(3, r.getMembersCount());

    assertFalse(r.isModified());
  }
  /**
   * My node is deleted, their node has the same id and version and is not deleted. => mine has
   * precedence
   */
  @Test
  public void nodeSimple_DeleteConflict_2() {
    Node n = new Node(new LatLon(0, 0));
    n.setOsmId(1, 1);
    n.setDeleted(true);
    my.addPrimitive(n);

    Node n1 = new Node(new LatLon(0, 0));
    n1.setOsmId(1, 1);
    their.addPrimitive(n1);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    Node n2 = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
    assertEquals(0, visitor.getConflicts().size());
    assertTrue(n2.isVisible());
    assertSame(n, n2);
    assertSame(n.getDataSet(), my);
    assertSame(n1.getDataSet(), their);
  }
  /**
   * their node has no assigned id (id == 0) and is semantically equal to one of my nodes with id ==
   * 0
   *
   * <p>=> merge it onto my node.
   */
  @Test
  public void nodeSimple_NoIdSemanticallyEqual() {

    Calendar cal = GregorianCalendar.getInstance();
    User myUser = User.createOsmUser(1111, "my");

    User theirUser = User.createOsmUser(222, "their");

    Node n = new Node();
    n.setCoor(new LatLon(0, 0));
    n.put("key1", "value1");
    n.setUser(myUser);
    n.setTimestamp(cal.getTime());

    my.addPrimitive(n);

    Node n1 = new Node();
    n1.setCoor(new LatLon(0, 0));
    n1.put("key1", "value1");
    cal.add(Calendar.HOUR, 1);
    Date timestamp = cal.getTime();
    n1.setTimestamp(timestamp);
    n1.setUser(theirUser);
    their.addPrimitive(n1);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    Node n2 = my.getNodes().iterator().next();
    assertEquals(0, visitor.getConflicts().size());
    assertEquals("value1", n2.get("key1"));
    assertEquals(n1.getRawTimestamp(), n2.getRawTimestamp());
    assertEquals(theirUser, n2.getUser());
    assertSame(n2, n);
    assertNotSame(n2, n1);
    assertSame(n2.getDataSet(), my);
  }
  /**
   * Merge an incomplete way with two incomplete nodes into an empty dataset.
   *
   * <p>Use case: a way loaded with a multiget, i.e. GET /api/0.6/ways?ids=123456
   */
  @Test
  public void newIncompleteWay() {

    Node n1 = new Node(1);
    their.addPrimitive(n1);

    Node n2 = new Node(2);
    their.addPrimitive(n2);

    Way w3 = new Way(3);
    w3.setNodes(Arrays.asList(n1, n2));
    their.addPrimitive(w3);
    assertTrue(w3.isIncomplete());

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    assertEquals(0, visitor.getConflicts().size());

    OsmPrimitive p = my.getPrimitiveById(1, OsmPrimitiveType.NODE);
    assertNotNull(p);
    assertTrue(p.isIncomplete());
    p = my.getPrimitiveById(2, OsmPrimitiveType.NODE);
    assertNotNull(p);
    assertTrue(p.isIncomplete());
    p = my.getPrimitiveById(3, OsmPrimitiveType.WAY);
    assertNotNull(p);
    assertTrue(p.isIncomplete());

    Way w = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
    assertNotNull(w);
    assertTrue(p.isIncomplete());
    assertEquals(2, w.getNodesCount());
    assertTrue(w.getNode(0).isIncomplete());
    assertTrue(w.getNode(1).isIncomplete());
  }
  /**
   * their way is not visible anymore.
   *
   * <p>=> conflict
   */
  @Test
  public void waySimple_TheirVersionNotVisibleMyIsModified() {

    Node mn1 = new Node(new LatLon(0, 0));
    mn1.setOsmId(1, 1);
    my.addPrimitive(mn1);

    Node mn2 = new Node(new LatLon(1, 1));
    mn2.setOsmId(2, 1);
    my.addPrimitive(mn2);

    Way myWay = new Way();
    myWay.setOsmId(3, 1);
    myWay.addNode(mn1);
    myWay.addNode(mn2);
    myWay.setModified(true);
    my.addPrimitive(myWay);

    Way theirWay = new Way();
    theirWay.setOsmId(3, 2);
    theirWay.setVisible(false);
    /* Invisible objects fetched from the server should be marked as "deleted".
     * Otherwise it's an error.
     */
    theirWay.setDeleted(true);
    their.addPrimitive(theirWay);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    Way merged = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
    assertEquals(1, visitor.getConflicts().size());
    assertTrue(visitor.getConflicts().hasConflictForMy(myWay));
    assertTrue(visitor.getConflicts().hasConflictForTheir(theirWay));
    assertEquals(myWay, merged);
  }
  /**
   * my node is incomplete, their node is complete
   *
   * <p>=> merge it onto my node. My node becomes complete
   */
  @Test
  public void nodeSimple_IncompleteNode() {

    Node n = new Node(1);
    my.addPrimitive(n);

    Node n1 = new Node();
    n1.setCoor(new LatLon(0, 0));
    n1.setOsmId(1, 1);
    n1.put("key1", "value1");
    Date timestamp = new Date();
    n1.setTimestamp(timestamp);
    their.addPrimitive(n1);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    Node n2 = my.getNodes().iterator().next();
    assertEquals(0, visitor.getConflicts().size());
    assertEquals("value1", n2.get("key1"));
    assertEquals(n1.getRawTimestamp(), n2.getRawTimestamp());
    assertFalse(n2.isIncomplete());
    assertSame(n2, n);
  }
  /**
   * their way has a higher version and different tags. And it has more nodes. Two of the existing
   * nodes are modified.
   *
   * <p>=> merge it onto my way, no conflict
   */
  @Test
  public void waySimple_AdditionalNodesAndChangedNodes() {

    // -- my data set

    Node n1 = new Node(new LatLon(0, 0));
    n1.setOsmId(1, 1);
    my.addPrimitive(n1);

    Node n2 = new Node(new LatLon(1, 1));
    n2.setOsmId(2, 1);
    my.addPrimitive(n2);

    Way myWay = new Way();
    myWay.setOsmId(3, 1);
    myWay.addNode(n1);
    myWay.addNode(n2);
    my.addPrimitive(myWay);

    // --- their data set

    Node n3 = new Node(new LatLon(0, 0));
    n3.setOsmId(1, 1);
    their.addPrimitive(n3);

    Node n5 = new Node(new LatLon(1, 1));
    n5.setOsmId(4, 1);

    their.addPrimitive(n5);

    Node n4 = new Node(new LatLon(2, 2));
    n4.setOsmId(2, 2);
    n4.put("key1", "value1");
    their.addPrimitive(n4);

    Way theirWay = new Way();
    theirWay.setOsmId(3, 2);
    theirWay.addNode(n3);
    theirWay.addNode(n5); // insert a node
    theirWay.addNode(n4); // this one is updated
    their.addPrimitive(theirWay);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    // -- tests
    Way merged = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
    assertEquals(0, visitor.getConflicts().size());
    assertEquals(3, merged.getId());
    assertEquals(2, merged.getVersion());
    assertEquals(3, merged.getNodesCount());
    assertEquals(1, merged.getNode(0).getId());
    assertEquals(4, merged.getNode(1).getId());
    assertEquals(2, merged.getNode(2).getId());
    assertEquals("value1", merged.getNode(2).get("key1"));

    assertSame(merged.getNode(0), n1);
    assertNotSame(merged.getNode(1), n5); // must be clone of the original node in their
    assertSame(merged.getNode(2), n2);

    assertFalse(
        merged
            .isModified()); // the target wasn't modified before merging, it mustn't be after
                            // merging
  }
  /**
   * their way has a higher version and different tags. the nodes are the same. My way is not
   * modified. Merge is possible. No conflict.
   *
   * <p>=> merge it onto my way.
   */
  @Test
  public void waySimple_IdenicalNodesDifferentTags() {

    // -- the target dataset

    Node n1 = new Node();
    n1.setCoor(new LatLon(0, 0));
    n1.setOsmId(1, 1);
    my.addPrimitive(n1);

    Node n2 = new Node();
    n2.setCoor(new LatLon(0, 0));
    n2.setOsmId(2, 1);

    my.addPrimitive(n2);

    Way myWay = new Way();
    myWay.setOsmId(3, 1);
    myWay.put("key1", "value1");
    myWay.addNode(n1);
    myWay.addNode(n2);
    my.addPrimitive(myWay);

    // -- the source data set

    Node n3 = new Node(new LatLon(0, 0));
    n3.setOsmId(1, 1);
    their.addPrimitive(n3);

    Node n4 = new Node(new LatLon(1, 1));
    n4.setOsmId(2, 1);
    their.addPrimitive(n4);

    Way theirWay = new Way();
    theirWay.setOsmId(3, 2);
    theirWay.put("key1", "value1");
    theirWay.put("key2", "value2");
    theirWay.addNode(n3);
    theirWay.addNode(n4);
    their.addPrimitive(theirWay);

    DataSetMerger visitor = new DataSetMerger(my, their);
    visitor.merge();

    // -- tests
    Way merged = (Way) my.getPrimitiveById(3, OsmPrimitiveType.WAY);
    assertEquals(0, visitor.getConflicts().size());
    assertEquals("value1", merged.get("key1"));
    assertEquals("value2", merged.get("key2"));
    assertEquals(3, merged.getId());
    assertEquals(2, merged.getVersion());
    assertEquals(2, merged.getNodesCount());
    assertEquals(1, merged.getNode(0).getId());
    assertEquals(2, merged.getNode(1).getId());
    assertSame(merged, myWay);
    assertSame(merged.getDataSet(), my);

    Node mergedNode = (Node) my.getPrimitiveById(1, OsmPrimitiveType.NODE);
    assertSame(mergedNode, n1);
    mergedNode = (Node) my.getPrimitiveById(2, OsmPrimitiveType.NODE);
    assertSame(mergedNode, n2);

    assertFalse(merged.isModified());
  }