From 0bd5ce3174b2f211bb459d719133155868dcd744 Mon Sep 17 00:00:00 2001
From: Robert Scott <code@humanleg.org.uk>
Date: Sat, 17 Mar 2018 19:35:03 +0000
Subject: [PATCH v2 07/28] JOSMTestRules: add EDTAssertionMocker and
 .assertionsInEDT() method for controlling it

This should allow tests to throw assertions from *within* the EDT and have
them cause a test failure.
---
 src/org/openstreetmap/josm/gui/util/GuiHelper.java | 10 ++++++---
 .../josm/testutils/JOSMTestRules.java              | 24 ++++++++++++++++++++++
 .../josm/testutils/mockers/EDTAssertionMocker.java | 24 ++++++++++++++++++++++
 3 files changed, 55 insertions(+), 3 deletions(-)
 create mode 100644 test/unit/org/openstreetmap/josm/testutils/mockers/EDTAssertionMocker.java

diff --git a/src/org/openstreetmap/josm/gui/util/GuiHelper.java b/src/org/openstreetmap/josm/gui/util/GuiHelper.java
index e11f26f9d..c7b9df753 100644
--- a/src/org/openstreetmap/josm/gui/util/GuiHelper.java
+++ b/src/org/openstreetmap/josm/gui/util/GuiHelper.java
@@ -201,6 +201,10 @@ public final class GuiHelper {
         }
     }
 
+    private static void handleEDTException(Throwable t) {
+        Logging.logWithStackTrace(Logging.LEVEL_ERROR, t, "Exception raised in EDT");
+    }
+
     /**
      * Executes synchronously a runnable in
      * <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html">Event Dispatch Thread</a>.
@@ -214,7 +218,7 @@ public final class GuiHelper {
             try {
                 SwingUtilities.invokeAndWait(task);
             } catch (InterruptedException | InvocationTargetException e) {
-                Logging.error(e);
+                handleEDTException(e);
             }
         }
     }
@@ -255,7 +259,7 @@ public final class GuiHelper {
             try {
                 return callable.call();
             } catch (Exception e) { // NOPMD
-                Logging.error(e);
+                handleEDTException(e);
                 return null;
             }
         } else {
@@ -264,7 +268,7 @@ public final class GuiHelper {
             try {
                 return task.get();
             } catch (InterruptedException | ExecutionException e) {
-                Logging.error(e);
+                handleEDTException(e);
                 return null;
             }
         }
diff --git a/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java b/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
index 24394108f..03d7cb3b8 100644
--- a/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
+++ b/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
@@ -65,6 +65,7 @@ public class JOSMTestRules implements TestRule {
     private Version originalVersion;
     private Runnable mapViewStateMockingRunnable;
     private Runnable navigableComponentMockingRunnable;
+    private Runnable edtAssertionMockingRunnable;
     private boolean platform;
     private boolean useProjection;
     private boolean useProjectionNadGrids;
@@ -261,6 +262,25 @@ public class JOSMTestRules implements TestRule {
     }
 
     /**
+     * Re-raise AssertionErrors thrown in the EDT where they would have normally been swallowed.
+     * @return this instance, for easy chaining
+     */
+    public JOSMTestRules assertionsInEDT() {
+        return this.assertionsInEDT(EDTAssertionMocker::new);
+    }
+
+    /**
+     * Re-raise AssertionErrors thrown in the EDT where they would have normally been swallowed.
+     * @param edtAssertionMockingRunnable Runnable for initializing this functionality
+     *
+     * @return this instance, for easy chaining
+     */
+    public JOSMTestRules assertionsInEDT(final Runnable edtAssertionMockingRunnable) {
+        this.edtAssertionMockingRunnable = edtAssertionMockingRunnable;
+        return this;
+    }
+
+    /**
      * Replace imagery sources with a default set of mock tile sources
      *
      * @return this instance, for easy chaining
@@ -472,6 +492,10 @@ public class JOSMTestRules implements TestRule {
             RightAndLefthandTraffic.initialize();
         }
 
+        if (this.edtAssertionMockingRunnable != null) {
+            this.edtAssertionMockingRunnable.run();
+        }
+
         if (commands) {
             // TODO: Implement a more selective version of this once Main is restructured.
             JOSMFixture.createUnitTestFixture().init(true);
diff --git a/test/unit/org/openstreetmap/josm/testutils/mockers/EDTAssertionMocker.java b/test/unit/org/openstreetmap/josm/testutils/mockers/EDTAssertionMocker.java
new file mode 100644
index 000000000..f9aaa388d
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/mockers/EDTAssertionMocker.java
@@ -0,0 +1,24 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils;
+
+import org.openstreetmap.josm.gui.util.GuiHelper;
+
+import mockit.Invocation;
+import mockit.Mock;
+import mockit.MockUp;
+
+/**
+ * MockUp that, when applied, should cause calls to the EDT which would normally swallow generated
+ * AssertionErrors to instead re-raise them.
+ */
+public class EDTAssertionMocker extends MockUp<GuiHelper> {
+    @Mock
+    private static void handleEDTException(final Invocation invocation, final Throwable t) {
+        final Throwable cause = t.getCause();
+        if (cause instanceof AssertionError) {
+            throw (AssertionError) cause;
+        }
+
+        invocation.proceed(t);
+    }
+}
-- 
2.11.0

