Index: trunk/test/unit/org/openstreetmap/josm/gui/io/UploadDialogTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/io/UploadDialogTest.java	(revision 14349)
+++ trunk/test/unit/org/openstreetmap/josm/gui/io/UploadDialogTest.java	(revision 14355)
@@ -2,14 +2,28 @@
 package org.openstreetmap.josm.gui.io;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import java.awt.GraphicsEnvironment;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
 
 import org.junit.Rule;
 import org.junit.Test;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.io.UploadStrategySpecification;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.mockers.ExtendedDialogMocker;
+import org.openstreetmap.josm.testutils.mockers.WindowMocker;
+
+import mockit.Invocation;
+import mockit.Mock;
+
+import com.google.common.collect.ImmutableMap;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -27,71 +41,162 @@
     public JOSMTestRules test = new JOSMTestRules().preferences();
 
-    private static IUploadDialog newUploadDialog(final String comment, final String source) {
-        return new IUploadDialog() {
-
-            @Override
-            public void rememberUserInput() {
-                // Do nothing
-            }
-
-            @Override
-            public boolean isCanceled() {
-                return false;
-            }
-
-            @Override
-            public void handleMissingSource() {
-                // Do nothing
-            }
-
-            @Override
-            public void handleMissingComment() {
-                // Do nothing
-            }
-
-            @Override
-            public void handleIllegalChunkSize() {
-                // Do nothing
-            }
-
-            @Override
-            public UploadStrategySpecification getUploadStrategySpecification() {
-                return new UploadStrategySpecification();
-            }
-
-            @Override
-            public String getUploadSource() {
-                return source;
-            }
-
-            @Override
-            public String getUploadComment() {
-                return comment;
-            }
-
-            @Override
-            public Map<String, String> getTags(boolean keepEmpty) {
-                return new ConcurrentHashMap<>();
+    private static class MockUploadDialog extends JOptionPane implements IUploadDialog {
+        private final String source;
+        private final String comment;
+
+        public int handleMissingCommentCalls;
+        public int handleMissingSourceCalls;
+
+        MockUploadDialog(final String comment, final String source) {
+            this.source = source;
+            this.comment = comment;
+        }
+
+        @Override
+        public void rememberUserInput() {
+            // Do nothing
+        }
+
+        @Override
+        public boolean isCanceled() {
+            return false;
+        }
+
+        @Override
+        public void handleMissingSource() {
+            this.handleMissingSourceCalls += 1;
+        }
+
+        @Override
+        public void handleMissingComment() {
+            this.handleMissingCommentCalls += 1;
+        }
+
+        @Override
+        public void handleIllegalChunkSize() {
+            // Do nothing
+        }
+
+        @Override
+        public UploadStrategySpecification getUploadStrategySpecification() {
+            return new UploadStrategySpecification();
+        }
+
+        @Override
+        public String getUploadSource() {
+            return source;
+        }
+
+        @Override
+        public String getUploadComment() {
+            return comment;
+        }
+
+        @Override
+        public Map<String, String> getTags(boolean keepEmpty) {
+            return new ConcurrentHashMap<>();
+        }
+    }
+
+    /**
+     * Test of {@link UploadDialog.CancelAction} class.
+     */
+    @Test
+    public void testCancelAction() {
+        if (GraphicsEnvironment.isHeadless()) {
+            TestUtils.assumeWorkingJMockit();
+            new WindowMocker();
+        }
+        MockUploadDialog uploadDialog = new MockUploadDialog(null, null);
+        new UploadDialog.CancelAction(uploadDialog).actionPerformed(null);
+    }
+
+    /**
+     * Test of {@link UploadDialog.UploadAction} class.
+     */
+    @Test
+    public void testUploadAction() {
+        TestUtils.assumeWorkingJMockit();
+        ExtendedDialogMocker edMocker = new ExtendedDialogMocker(
+            ImmutableMap.<String, Object>of(
+                "<html>Your upload comment is <i>empty</i>, or <i>very short</i>.<br /><br />This is "
+                + "technically allowed, but please consider that many users who are<br />watching changes "
+                + "in their area depend on meaningful changeset comments<br />to understand what is going "
+                + "on!<br /><br />If you spend a minute now to explain your change, you will make life<br />"
+                + "easier for many other mappers.</html>", "Revise",
+                "<html>You did not specify a source for your changes.<br />It is technically allowed, "
+                + "but this information helps<br />other users to understand the origins of the data."
+                + "<br /><br />If you spend a minute now to explain your change, you will make life"
+                + "<br />easier for many other mappers.</html>", "Revise"
+            )
+        ) {
+            @Mock
+            void setupDialog(Invocation invocation) throws Exception {
+                if (GraphicsEnvironment.isHeadless()) {
+                    final int nButtons = ((String[]) TestUtils.getPrivateField(
+                            ExtendedDialog.class, invocation.getInvokedInstance(), "bTexts")).length;
+                    @SuppressWarnings("unchecked")
+                    final List<JButton> buttons = (List<JButton>) TestUtils.getPrivateField(
+                            ExtendedDialog.class, invocation.getInvokedInstance(), "buttons");
+
+                    for (int i = 0; i < nButtons; i++) {
+                        buttons.add(new JButton());
+                    }
+                } else {
+                    invocation.proceed();
+                }
             }
         };
-    }
-
-    /**
-     * Test of {@link UploadDialog.CancelAction} class.
-     */
-    @Test
-    public void testCancelAction() {
-        new UploadDialog.CancelAction(newUploadDialog(null, null)).actionPerformed(null);
-    }
-
-    /**
-     * Test of {@link UploadDialog.UploadAction} class.
-     */
-    @Test
-    public void testUploadAction() {
-        new UploadDialog.UploadAction(newUploadDialog("comment", "source")).actionPerformed(null);
-        new UploadDialog.UploadAction(newUploadDialog("", "source")).actionPerformed(null);
-        new UploadDialog.UploadAction(newUploadDialog("comment", "")).actionPerformed(null);
-        new UploadDialog.UploadAction(newUploadDialog("a comment long enough", "a source long enough")).actionPerformed(null);
+
+        MockUploadDialog uploadDialog = new MockUploadDialog("comment", "source");
+        new UploadDialog.UploadAction(uploadDialog).actionPerformed(null);
+
+        assertEquals(1, uploadDialog.handleMissingCommentCalls);
+        assertEquals(0, uploadDialog.handleMissingSourceCalls);
+        assertEquals(1, edMocker.getInvocationLog().size());
+        Object[] invocationLogEntry = edMocker.getInvocationLog().get(0);
+        assertEquals(1, (int) invocationLogEntry[0]);
+        assertEquals("Please revise upload comment", invocationLogEntry[2]);
+        edMocker.resetInvocationLog();
+
+        uploadDialog = new MockUploadDialog("", "source");
+        new UploadDialog.UploadAction(uploadDialog).actionPerformed(null);
+
+        assertEquals(1, uploadDialog.handleMissingCommentCalls);
+        assertEquals(0, uploadDialog.handleMissingSourceCalls);
+        assertEquals(1, edMocker.getInvocationLog().size());
+        invocationLogEntry = edMocker.getInvocationLog().get(0);
+        assertEquals(1, (int) invocationLogEntry[0]);
+        assertEquals("Please revise upload comment", invocationLogEntry[2]);
+        edMocker.resetInvocationLog();
+
+        uploadDialog = new MockUploadDialog("comment", "");
+        new UploadDialog.UploadAction(uploadDialog).actionPerformed(null);
+
+        assertEquals(1, uploadDialog.handleMissingCommentCalls);
+        assertEquals(0, uploadDialog.handleMissingSourceCalls);
+        assertEquals(1, edMocker.getInvocationLog().size());
+        invocationLogEntry = edMocker.getInvocationLog().get(0);
+        assertEquals(1, (int) invocationLogEntry[0]);
+        assertEquals("Please revise upload comment", invocationLogEntry[2]);
+        edMocker.resetInvocationLog();
+
+        uploadDialog = new MockUploadDialog("a comment long enough", "");
+        new UploadDialog.UploadAction(uploadDialog).actionPerformed(null);
+
+        assertEquals(0, uploadDialog.handleMissingCommentCalls);
+        assertEquals(1, uploadDialog.handleMissingSourceCalls);
+        assertEquals(1, edMocker.getInvocationLog().size());
+        invocationLogEntry = edMocker.getInvocationLog().get(0);
+        assertEquals(1, (int) invocationLogEntry[0]);
+        assertEquals("Please specify a changeset source", invocationLogEntry[2]);
+        edMocker.resetInvocationLog();
+
+        uploadDialog = new MockUploadDialog("a comment long enough", "a source long enough");
+        new UploadDialog.UploadAction(uploadDialog).actionPerformed(null);
+
+        assertEquals(0, uploadDialog.handleMissingCommentCalls);
+        assertEquals(0, uploadDialog.handleMissingSourceCalls);
+        assertEquals(0, edMocker.getInvocationLog().size());
     }
 
Index: trunk/test/unit/org/openstreetmap/josm/testutils/mockers/BaseDialogMockUp.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/testutils/mockers/BaseDialogMockUp.java	(revision 14349)
+++ trunk/test/unit/org/openstreetmap/josm/testutils/mockers/BaseDialogMockUp.java	(revision 14355)
@@ -26,4 +26,11 @@
     }
 
+    /**
+     * Empties the invocation log.
+     */
+    public void resetInvocationLog() {
+        this.invocationLogInternal.clear();
+    }
+
     private final List<Object[]> invocationLogInternal = new ArrayList<>(4);
 
