Index: trunk/test/unit/org/openstreetmap/josm/actions/SessionSaveActionTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/actions/SessionSaveActionTest.java	(revision 18466)
+++ trunk/test/unit/org/openstreetmap/josm/actions/SessionSaveActionTest.java	(revision 18466)
@@ -0,0 +1,77 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.GpxLayer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.io.session.SessionWriterTest;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Unit tests for class {@link SessionSaveAsAction}.
+ */
+class SessionSaveActionTest {
+    /**
+     * Setup test.
+     */
+    @RegisterExtension
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().main().projection();
+
+    /**
+     * Unit test of {@link SessionSaveAction}
+     * @throws IOException Temp file could not be created
+     */
+    @Test
+    void testSaveAction() throws IOException {
+        TestUtils.assumeWorkingJMockit();
+
+        File jos = File.createTempFile("session", ".jos");
+        File joz = new File(jos.getAbsolutePath().replaceFirst(".jos$", ".joz"));
+        assertTrue(jos.exists());
+        assertFalse(joz.exists());
+
+        String overrideStr = "javax.swing.JLabel[,0,0,0x0,invalid,alignmentX=0.0,alignmentY=0.0,border=,flags=8388608,maximumSize=,minimumSize=,"
+                + "preferredSize=,defaultIcon=,disabledIcon=,horizontalAlignment=LEADING,horizontalTextPosition=TRAILING,iconTextGap=4,"
+                + "labelFor=,text=<html>The following layer has been removed since the session was last saved:<ul><li>OSM layer name</ul>"
+                + "<br>You are about to overwrite the session file \"" + joz.getName()
+                + "\". Would you like to proceed?,verticalAlignment=CENTER,verticalTextPosition=CENTER]";
+
+        SessionSaveAction saveAction = SessionSaveAction.getInstance();
+        saveAction.setEnabled(true);
+
+        OsmDataLayer osm = SessionWriterTest.createOsmLayer();
+        GpxLayer gpx = SessionWriterTest.createGpxLayer();
+
+        JOptionPaneSimpleMocker mocker = new JOptionPaneSimpleMocker(Collections.singletonMap(overrideStr, 0));
+        SessionSaveAction.setCurrentSession(jos, false, Arrays.asList(gpx, osm)); //gpx and OSM layer
+        MainApplication.getLayerManager().addLayer(gpx); //only gpx layer
+        saveAction.actionPerformed(null); //Complain that OSM layer was removed
+        assertEquals(1, mocker.getInvocationLog().size());
+        assertFalse(jos.exists());
+        assertTrue(joz.exists()); //converted jos to joz since the session includes files
+
+        mocker = new JOptionPaneSimpleMocker(Collections.singletonMap(overrideStr, 0));
+        joz.delete();
+        saveAction.actionPerformed(null); //Do not complain about removed layers
+        assertEquals(0, mocker.getInvocationLog().size());
+        assertTrue(joz.exists());
+
+        joz.delete();
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/actions/SessionSaveAsActionTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/actions/SessionSaveAsActionTest.java	(revision 18464)
+++ trunk/test/unit/org/openstreetmap/josm/actions/SessionSaveAsActionTest.java	(revision 18466)
@@ -4,6 +4,6 @@
 import static org.junit.jupiter.api.Assertions.assertFalse;
 
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
-import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
@@ -20,5 +20,5 @@
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules();
+    public JOSMTestRules test = new JOSMTestRules().main();
 
     /**
Index: trunk/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java	(revision 18464)
+++ trunk/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java	(revision 18466)
@@ -51,5 +51,5 @@
  * Unit tests for Session writing.
  */
-class SessionWriterTest {
+public class SessionWriterTest {
 
     protected static final class OsmHeadlessJosExporter extends OsmDataSessionExporter {
@@ -123,4 +123,5 @@
         for (final Layer l : layers) {
             SessionLayerExporter s = SessionWriter.getSessionLayerExporter(l);
+            s.getExportPanel();
             exporters.put(l, s);
             if (s instanceof GpxTracksSessionExporter) {
@@ -154,5 +155,10 @@
     }
 
-    private OsmDataLayer createOsmLayer() {
+    /**
+     * Creates an OSM layer
+     * @return OSM layer
+     * @since 18466
+     */
+    public static OsmDataLayer createOsmLayer() {
         OsmDataLayer layer = new OsmDataLayer(new DataSet(), "OSM layer name", null);
         layer.setAssociatedFile(new File("data.osm"));
@@ -160,5 +166,10 @@
     }
 
-    private GpxLayer createGpxLayer() {
+    /**
+     * Creates a GPX layer
+     * @return GPX layer
+     * @since 18466
+     */
+    public static GpxLayer createGpxLayer() {
         GpxData data = new GpxData();
         WayPoint wp = new WayPoint(new LatLon(42.72665, -0.00747));
@@ -171,12 +182,24 @@
     }
 
-    private MarkerLayer createMarkerLayer(GpxLayer gpx) {
+    /**
+     * Creates a MarkerLayer
+     * @param gpx linked GPX layer
+     * @return MarkerLayer
+     * @since 18466
+     */
+    public static MarkerLayer createMarkerLayer(GpxLayer gpx) {
         MarkerLayer layer = new MarkerLayer(gpx.data, "Marker layer name", gpx.getAssociatedFile(), gpx);
         layer.setOpacity(0.5);
         layer.setColor(new Color(0x12345678, true));
+        gpx.setLinkedMarkerLayer(layer);
         return layer;
     }
 
-    private ImageryLayer createImageryLayer() {
+    /**
+     * Creates an ImageryLayer
+     * @return ImageryLayer
+     * @since 18466
+     */
+    public static ImageryLayer createImageryLayer() {
         TMSLayer layer = new TMSLayer(new ImageryInfo("the name", "http://www.url.com/"));
         layer.getDisplaySettings().setOffsetBookmark(
@@ -185,5 +208,10 @@
     }
 
-    private NoteLayer createNoteLayer() {
+    /**
+     * Creates a NoteLayer
+     * @return NoteLayer
+     * @since 18466
+     */
+    public static NoteLayer createNoteLayer() {
         return new NoteLayer(Arrays.asList(new Note(LatLon.ZERO)), "layer name");
     }
@@ -250,7 +278,8 @@
     void testWriteGpxAndMarkerJoz() throws IOException {
         GpxLayer gpx = createGpxLayer();
-        Map<String, byte[]> bytes = testWrite(Arrays.asList(gpx, createMarkerLayer(gpx)), true);
-
-        Path path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers.jos");
+        MarkerLayer markers = createMarkerLayer(gpx);
+        Map<String, byte[]> bytes = testWrite(Arrays.asList(gpx, markers), true);
+
+        Path path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers_combined.jos");
         String expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
         String actual = new String(bytes.get("session.jos"), StandardCharsets.UTF_8).replace("\r", "");
@@ -262,8 +291,25 @@
         assertEquals(expected, actual);
 
+        //Test writing when the marker layer has no corresponding GPX layer:
+        gpx.setLinkedMarkerLayer(null);
+        markers.fromLayer = null;
+        markers.data.transferLayerPrefs(gpx.data.getLayerPrefs());
+        bytes = testWrite(Arrays.asList(gpx, markers), true);
+
+        path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/gpx_markers.jos");
+        expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
+        actual = new String(bytes.get("session.jos"), StandardCharsets.UTF_8).replace("\r", "");
+        assertEquals(expected, actual);
+
+        path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/data_export.gpx");
+        expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
+        actual = new String(bytes.get("layers/01/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
+        assertEquals(expected, actual);
+
         path = Paths.get(TestUtils.getTestDataRoot() + "/sessions/markers.gpx");
         expected = new String(Files.readAllBytes(path), StandardCharsets.UTF_8).replace("\r", "");
         actual = new String(bytes.get("layers/02/data.gpx"), StandardCharsets.UTF_8).replace("\r", "");
         assertEquals(expected, actual);
+
     }
 
