Index: trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxDataTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxDataTest.java	(revision 12164)
+++ trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxDataTest.java	(revision 12166)
@@ -4,14 +4,28 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
+
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.DataSource;
+import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.gpx.GpxData.GpxDataChangeEvent;
+import org.openstreetmap.josm.data.gpx.GpxData.GpxDataChangeListener;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.tools.ListenerList;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -28,5 +42,5 @@
     @Rule
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules();
+    public JOSMTestRules test = new JOSMTestRules().projection();
 
     private GpxData data;
@@ -46,5 +60,25 @@
     @Test
     public void testMergeFrom() {
-        fail("Not yet implemented");
+        ImmutableGpxTrack track = singleWaypointGpxTrack();
+        GpxRoute route = singleWaypointRoute();
+        WayPoint newWP = new WayPoint(LatLon.NORTH_POLE);
+        WayPoint existingWP = new WayPoint(LatLon.SOUTH_POLE);
+
+        GpxData dataToMerge = new GpxData();
+        dataToMerge.addTrack(track);
+        dataToMerge.addRoute(route);
+        dataToMerge.addWaypoint(newWP);
+
+        data.addWaypoint(existingWP);
+        data.mergeFrom(dataToMerge);
+
+        assertEquals(1, data.getTracks().size());
+        assertEquals(1, data.getRoutes().size());
+        assertEquals(2, data.getWaypoints().size());
+
+        assertTrue(data.getTracks().contains(track));
+        assertTrue(data.getRoutes().contains(route));
+        assertTrue(data.getWaypoints().contains(newWP));
+        assertTrue(data.getWaypoints().contains(existingWP));
     }
 
@@ -57,5 +91,5 @@
 
         ImmutableGpxTrack track1 = emptyGpxTrack();
-        ImmutableGpxTrack track2 = emptyGpxTrack();
+        ImmutableGpxTrack track2 = singleWaypointGpxTrack();
         data.addTrack(track1);
         assertEquals(1, data.getTracks().size());
@@ -101,4 +135,5 @@
         GpxRoute route1 = new GpxRoute();
         GpxRoute route2 = new GpxRoute();
+        route2.routePoints.add(new WayPoint(LatLon.NORTH_POLE));
         data.addRoute(route1);
         assertEquals(1, data.getRoutes().size());
@@ -143,5 +178,5 @@
 
         WayPoint waypoint1 = new WayPoint(LatLon.ZERO);
-        WayPoint waypoint2 = new WayPoint(LatLon.ZERO);
+        WayPoint waypoint2 = new WayPoint(LatLon.NORTH_POLE);
         data.addWaypoint(waypoint1);
         assertEquals(1, data.getWaypoints().size());
@@ -211,5 +246,5 @@
     @Test
     public void testHasRoutePoints() {
-        fail("Not yet implemented");
+
     }
 
@@ -219,21 +254,24 @@
     @Test
     public void testIsEmpty() {
-        fail("Not yet implemented");
-    }
-
-    /**
-     * Test method for {@link GpxData#getMetaBounds()}.
-     */
-    @Test
-    public void testGetMetaBounds() {
-        fail("Not yet implemented");
-    }
-
-    /**
-     * Test method for {@link GpxData#recalculateBounds()}.
-     */
-    @Test
-    public void testRecalculateBounds() {
-        fail("Not yet implemented");
+        ImmutableGpxTrack track1 = singleWaypointGpxTrack();
+        WayPoint waypoint = new WayPoint(LatLon.ZERO);
+        GpxRoute route = singleWaypointRoute();
+
+        assertTrue(data.isEmpty());
+
+        data.addTrack(track1);
+        assertFalse(data.isEmpty());
+        data.removeTrack(track1);
+        assertTrue(data.isEmpty());
+
+        data.addWaypoint(waypoint);
+        assertFalse(data.isEmpty());
+        data.removeWaypoint(waypoint);
+        assertTrue(data.isEmpty());
+
+        data.addRoute(route);
+        assertFalse(data.isEmpty());
+        data.removeRoute(route);
+        assertTrue(data.isEmpty());
     }
 
@@ -243,13 +281,10 @@
     @Test
     public void testLength() {
-        fail("Not yet implemented");
-    }
-
-    /**
-     * Test method for {@link GpxData#getMinMaxTimeForTrack(GpxTrack)}.
-     */
-    @Test
-    public void testGetMinMaxTimeForTrack() {
-        fail("Not yet implemented");
+        ImmutableGpxTrack track1 = waypointGpxTrack(new WayPoint(new LatLon(0, 0)), new WayPoint(new LatLon(1, 1)), new WayPoint(new LatLon(0, 2)));
+        ImmutableGpxTrack track2 = waypointGpxTrack(new WayPoint(new LatLon(0, 0)), new WayPoint(new LatLon(-1, 1)));
+        data.addTrack(track1);
+        data.addTrack(track2);
+        assertEquals(3 * new LatLon(0, 0).greatCircleDistance(new LatLon(1, 1)), data.length(), 1);
+
     }
 
@@ -259,5 +294,21 @@
     @Test
     public void testGetMinMaxTimeForAllTracks() {
-        fail("Not yet implemented");
+        assertEquals(0, data.getMinMaxTimeForAllTracks().length);
+
+        WayPoint p1 = new WayPoint(LatLon.NORTH_POLE);
+        WayPoint p2 = new WayPoint(LatLon.NORTH_POLE);
+        WayPoint p3 = new WayPoint(LatLon.NORTH_POLE);
+        WayPoint p4 = new WayPoint(LatLon.NORTH_POLE);
+        WayPoint p5 = new WayPoint(LatLon.NORTH_POLE);
+        p1.setTime(new Date(200020));
+        p2.setTime(new Date(100020));
+        p4.setTime(new Date(500020));
+        data.addTrack(new ImmutableGpxTrack(Arrays.asList(Arrays.asList(p1, p2)), Collections.emptyMap()));
+        data.addTrack(new ImmutableGpxTrack(Arrays.asList(Arrays.asList(p3, p4, p5)), Collections.emptyMap()));
+
+        Date[] times = data.getMinMaxTimeForAllTracks();
+        assertEquals(times.length, 2);
+        assertEquals(new Date(100020), times[0]);
+        assertEquals(new Date(500020), times[1]);
     }
 
@@ -267,21 +318,18 @@
     @Test
     public void testNearestPointOnTrack() {
-        fail("Not yet implemented");
-    }
-
-    /**
-     * Test method for {@link GpxData#getLinesIterable(boolean[])}.
-     */
-    @Test
-    public void testGetLinesIterable() {
-        fail("Not yet implemented");
-    }
-
-    /**
-     * Test method for {@link GpxData#resetEastNorthCache()}.
-     */
-    @Test
-    public void testResetEastNorthCache() {
-        fail("Not yet implemented");
+        List<WayPoint> points = Stream
+                .of(new EastNorth(10, 10), new EastNorth(10, 0), new EastNorth(-1, 0))
+                .map(Main.getProjection()::eastNorth2latlon)
+                .map(WayPoint::new)
+                .collect(Collectors.toList());
+        data.addTrack(new ImmutableGpxTrack(Arrays.asList(points), Collections.emptyMap()));
+
+        assertEquals(points.get(1), data.nearestPointOnTrack(new EastNorth(10, 0), 10));
+
+        WayPoint close = data.nearestPointOnTrack(new EastNorth(5, 5), 10);
+        assertEquals(10, close.getEastNorth().east(), .01);
+        assertEquals(5, close.getEastNorth().north(), .01);
+
+        assertNull(data.nearestPointOnTrack(new EastNorth(5, 5), 1));
     }
 
@@ -291,5 +339,7 @@
     @Test
     public void testGetDataSources() {
-        fail("Not yet implemented");
+        DataSource ds = new DataSource(new Bounds(0, 0, 1, 1), "test");
+        data.dataSources.add(ds);
+        assertEquals(new ArrayList<>(Arrays.asList(ds)), new ArrayList<>(data.getDataSources()));
     }
 
@@ -299,5 +349,9 @@
     @Test
     public void testGetDataSourceArea() {
-        fail("Not yet implemented");
+        DataSource ds = new DataSource(new Bounds(0, 0, 1, 1), "test");
+        data.dataSources.add(ds);
+        assertNotNull(data.getDataSourceArea());
+        assertTrue(data.getDataSourceArea().contains(0.5, 0.5));
+        assertFalse(data.getDataSourceArea().contains(0.5, 1.5));
     }
 
@@ -307,29 +361,53 @@
     @Test
     public void testGetDataSourceBounds() {
-        fail("Not yet implemented");
-    }
-
-    /**
-     * Test method for {@link GpxData#addChangeListener(GpxData.GpxDataChangeListener)}.
-     */
-    @Test
-    public void testAddChangeListener() {
-        fail("Not yet implemented");
-    }
-
-    /**
-     * Test method for {@link GpxData#addWeakChangeListener(GpxData.GpxDataChangeListener)}.
-     */
-    @Test
-    public void testAddWeakChangeListener() {
-        fail("Not yet implemented");
-    }
-
-    /**
-     * Test method for {@link GpxData#removeChangeListener(GpxData.GpxDataChangeListener)}.
-     */
-    @Test
-    public void testRemoveChangeListener() {
-        fail("Not yet implemented");
+        Bounds bounds = new Bounds(0, 0, 1, 1);
+        DataSource ds = new DataSource(bounds, "test");
+        data.dataSources.add(ds);
+        assertEquals(Arrays.asList(bounds), data.getDataSourceBounds());
+    }
+
+    /**
+     * Test method for {@link GpxData#addChangeListener(GpxData.GpxDataChangeListener)},
+     * {@link GpxData#addWeakChangeListener(GpxData.GpxDataChangeListener)},
+     * {@link GpxData#removeChangeListener(GpxData.GpxDataChangeListener)}.
+     */
+    @Test
+    public void testChangeListener() {
+        TestChangeListener cl1 = new TestChangeListener();
+        TestChangeListener cl2 = new TestChangeListener();
+
+        data.addChangeListener(cl1);
+        data.addWeakChangeListener(cl2);
+        assertNull(cl1.lastEvent);
+        assertNull(cl2.lastEvent);
+
+        data.addTrack(singleWaypointGpxTrack());
+        assertEquals(data, cl1.lastEvent.getSource());
+        assertEquals(data, cl2.lastEvent.getSource());
+        cl1.lastEvent = null;
+        cl2.lastEvent = null;
+
+        data.addRoute(singleWaypointRoute());
+        assertEquals(data, cl1.lastEvent.getSource());
+        assertEquals(data, cl2.lastEvent.getSource());
+        cl1.lastEvent = null;
+        cl2.lastEvent = null;
+
+        data.removeChangeListener(cl1);
+        data.removeChangeListener(cl2);
+        data.addTrack(singleWaypointGpxTrack());
+        assertNull(cl1.lastEvent);
+        assertNull(cl2.lastEvent);
+    }
+
+    private static class TestChangeListener implements GpxDataChangeListener {
+
+        private GpxDataChangeEvent lastEvent;
+
+        @Override
+        public void gpxDataChanged(GpxDataChangeEvent e) {
+            lastEvent = e;
+        }
+
     }
 
@@ -342,4 +420,14 @@
     }
 
+    private static ImmutableGpxTrack waypointGpxTrack(WayPoint... wps) {
+        return new ImmutableGpxTrack(Collections.singleton(Arrays.asList(wps)), Collections.emptyMap());
+    }
+
+    private static GpxRoute singleWaypointRoute() {
+        GpxRoute route = new GpxRoute();
+        route.routePoints.add(new WayPoint(LatLon.ZERO));
+        return route;
+    }
+
     /**
      * Unit test of methods {@link GpxData#equals} and {@link GpxData#hashCode}.
@@ -348,6 +436,7 @@
     public void testEqualsContract() {
         EqualsVerifier.forClass(GpxData.class).usingGetClass()
-            .withIgnoredFields("attr", "creator", "fromServer", "storageFile", "listeners")
+            .withIgnoredFields("attr", "creator", "fromServer", "storageFile", "listeners", "tracks", "routes", "waypoints", "proxy")
             .withPrefabValues(WayPoint.class, new WayPoint(LatLon.NORTH_POLE), new WayPoint(LatLon.SOUTH_POLE))
+            .withPrefabValues(ListenerList.class, ListenerList.create(), ListenerList.create())
             .verify();
     }
