Index: trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetTest.java	(revision 15607)
+++ trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetTest.java	(revision 15609)
@@ -14,5 +14,9 @@
 import org.junit.Rule;
 import org.junit.Test;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.DataSource;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.event.DataSourceAddedEvent;
+import org.openstreetmap.josm.data.osm.event.DataSourceRemovedEvent;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
@@ -248,3 +252,39 @@
         assertTrue(UploadPolicy.DISCOURAGED.compareTo(UploadPolicy.NORMAL) > 0);
     }
+
+    /**
+     * Checks that data source listeners get called when a data source is added
+     */
+    @Test
+    public void testAddDataSourceListener() {
+        DataSourceListener addListener = new DataSourceListener() {
+            @Override
+            public void dataSourceChange(DataSourceChangeEvent event) {
+                assertTrue(event instanceof DataSourceAddedEvent);
+            }
+        };
+
+        DataSet ds = new DataSet();
+        ds.addDataSourceListener(addListener);
+        ds.addDataSource(new DataSource(new Bounds(0, 0, 0.1, 0.1), "fake source"));
+
+    }
+
+    /**
+     * Checks that data source listeners get called when a data source is removed
+     */
+    @Test
+    public void testRemoveDataSourceListener() {
+        DataSourceListener removeListener = new DataSourceListener() {
+            @Override
+            public void dataSourceChange(DataSourceChangeEvent event) {
+                assertTrue(event instanceof DataSourceRemovedEvent);
+            }
+        };
+
+        DataSet ds = new DataSet();
+        ds.addDataSource(new DataSource(new Bounds(0, 0, 0.1, 0.1), "fake source"));
+        ds.addDataSourceListener(removeListener);
+        new DataSet().mergeFrom(ds);
+    }
 }
Index: trunk/test/unit/org/openstreetmap/josm/data/osm/event/DataSourceAddedEventTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/data/osm/event/DataSourceAddedEventTest.java	(revision 15609)
+++ trunk/test/unit/org/openstreetmap/josm/data/osm/event/DataSourceAddedEventTest.java	(revision 15609)
@@ -0,0 +1,84 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm.event;
+
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.DataSource;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.DataSourceChangeEvent;
+
+/**
+ * Test class for {@link DataSourceAddedEvent}
+ *
+ * @author Taylor Smock
+ */
+public class DataSourceAddedEventTest {
+    /**
+     * Get getting the originating data source
+     */
+    @Test
+    public void testGetDataEventSource() {
+        DataSource fakeAdd = new DataSource(new Bounds(0, 0, 0, 0), "fake-source");
+        DataSet ds = new DataSet();
+        assertSame(ds, new DataSourceAddedEvent(ds, Collections.emptySet(), Stream.of(fakeAdd)).getSource());
+    }
+
+    /**
+     * Test that added sources are processed properly
+     */
+    @Test
+    public void testGetAddedSource() {
+        DataSource fakeAdd = new DataSource(new Bounds(0, 0, 0, 0), "fake-source");
+        assertTrue(
+                new DataSourceAddedEvent(new DataSet(), Collections.emptySet(), Stream.empty()).getAdded().isEmpty());
+        DataSourceChangeEvent event = new DataSourceAddedEvent(new DataSet(), Collections.emptySet(),
+                Stream.of(fakeAdd));
+        assertSame(event.getAdded(), event.getAdded());
+        assertSame(fakeAdd, new DataSourceAddedEvent(new DataSet(), Collections.emptySet(), Stream.of(fakeAdd))
+                .getAdded().iterator().next());
+    }
+
+    /**
+     * Test that there are no removed sources
+     */
+    @Test
+    public void testGetRemovedSource() {
+        DataSource fakeAdd = new DataSource(new Bounds(0, 0, 0, 0), "fake-source");
+        assertTrue(
+                new DataSourceAddedEvent(new DataSet(), Collections.emptySet(), Stream.empty()).getRemoved().isEmpty());
+        DataSourceChangeEvent event = new DataSourceAddedEvent(new DataSet(), Collections.emptySet(),
+                Stream.of(fakeAdd));
+        assertSame(event.getRemoved(), event.getRemoved());
+        assertTrue(new DataSourceAddedEvent(new DataSet(), Collections.emptySet(), Stream.of(fakeAdd)).getRemoved()
+                .isEmpty());
+    }
+
+    /**
+     * Check that the sources include newly added data
+     */
+    @Test
+    public void testGetDataSources() {
+        DataSource fakeAdd = new DataSource(new Bounds(0, 0, 0, 0), "fake-source");
+        DataSourceChangeEvent event = new DataSourceAddedEvent(new DataSet(), Collections.emptySet(),
+                Stream.of(fakeAdd));
+        assertSame(event.getDataSources(), event.getDataSources());
+        assertSame(fakeAdd, event.getDataSources().iterator().next());
+    }
+
+    /**
+     * Check that a string is returned with added/current/deleted
+     */
+    @Test
+    public void testToString() {
+        String toString = new DataSourceAddedEvent(new DataSet(), Collections.emptySet(), Stream.empty()).toString();
+        assertTrue(toString.contains("added"));
+        assertTrue(toString.contains("current"));
+        assertTrue(toString.contains("removed"));
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/data/osm/event/DataSourceRemovedEventTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/data/osm/event/DataSourceRemovedEventTest.java	(revision 15609)
+++ trunk/test/unit/org/openstreetmap/josm/data/osm/event/DataSourceRemovedEventTest.java	(revision 15609)
@@ -0,0 +1,91 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm.event;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.DataSource;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.DataSourceChangeEvent;
+
+/**
+ * Test class for {@link DataSourceRemovedEvent}
+ *
+ * @author Taylor Smock
+ */
+
+public class DataSourceRemovedEventTest {
+    /**
+     * Get getting the originating data source
+     */
+    @Test
+    public void testGetDataEventSource() {
+        DataSource fakeRemove = new DataSource(new Bounds(0, 0, 0, 0), "fake-source");
+        DataSet ds = new DataSet();
+        assertSame(ds, new DataSourceRemovedEvent(ds, Collections.emptySet(), Stream.of(fakeRemove)).getSource());
+    }
+
+    /**
+     * Test that no sources are added
+     */
+    @Test
+    public void testGetAddedSource() {
+        DataSource fakeRemove = new DataSource(new Bounds(0, 0, 0, 0), "fake-source");
+        assertTrue(
+                new DataSourceRemovedEvent(new DataSet(), Collections.emptySet(), Stream.empty()).getAdded().isEmpty());
+        DataSourceChangeEvent event = new DataSourceRemovedEvent(new DataSet(), Collections.emptySet(),
+                Stream.of(fakeRemove));
+        assertSame(event.getAdded(), event.getAdded());
+        assertTrue(new DataSourceRemovedEvent(new DataSet(), Collections.emptySet(), Stream.of(fakeRemove)).getAdded()
+                .isEmpty());
+    }
+
+    /**
+     * Test that the getting the removed source(s) works properly
+     */
+    @Test
+    public void testGetRemovedSource() {
+        DataSource fakeRemove = new DataSource(new Bounds(0, 0, 0, 0), "fake-source");
+        assertTrue(new DataSourceRemovedEvent(new DataSet(), Collections.emptySet(), Stream.empty()).getRemoved()
+                .isEmpty());
+        DataSourceChangeEvent event = new DataSourceRemovedEvent(new DataSet(), Collections.emptySet(),
+                Stream.of(fakeRemove));
+        assertSame(event.getRemoved(), event.getRemoved());
+        assertSame(fakeRemove, new DataSourceRemovedEvent(new DataSet(), Collections.emptySet(), Stream.of(fakeRemove))
+                .getRemoved().iterator().next());
+    }
+
+    /**
+     * Check that the sources don't include removed data
+     */
+    @Test
+    public void testGetDataSources() {
+        DataSource fakeRemove = new DataSource(new Bounds(0, 0, 0, 0), "fake-source");
+        DataSourceChangeEvent event = new DataSourceRemovedEvent(new DataSet(), Collections.emptySet(),
+                Stream.of(fakeRemove));
+        assertSame(event.getDataSources(), event.getDataSources());
+        assertFalse(event.getDataSources().contains(fakeRemove));
+        assertTrue(new DataSourceRemovedEvent(new DataSet(), Collections.singleton(fakeRemove), Stream.of(fakeRemove))
+                .getDataSources().isEmpty());
+        assertSame(fakeRemove,
+                new DataSourceRemovedEvent(new DataSet(), Collections.singleton(fakeRemove), Stream.empty())
+                        .getDataSources().iterator().next());
+    }
+
+    /**
+     * Check that a string is returned with added/current/deleted
+     */
+    @Test
+    public void testToString() {
+        String toString = new DataSourceRemovedEvent(new DataSet(), Collections.emptySet(), Stream.empty()).toString();
+        assertTrue(toString.contains("added"));
+        assertTrue(toString.contains("current"));
+        assertTrue(toString.contains("removed"));
+    }
+}
