Changeset 14052 in josm


Ignore:
Timestamp:
2018-07-26T22:01:31+02:00 (7 months ago)
Author:
Don-vip
Message:

see #16010 - use JMockit to enable more extensive test coverage (patch by ris, modified)

see https://github.com/openstreetmap/josm/pull/24/commits for details

Location:
trunk
Files:
17 added
2 deleted
25 edited

Legend:

Unmodified
Added
Removed
  • trunk/.classpath

    r14033 r14052  
    159159                </attributes>
    160160        </classpathentry>
     161        <classpathentry kind="lib" path="test/lib/jmockit-1.40.jar" sourcepath="C:/Users/vippy/.m2/repository/org/jmockit/jmockit/1.40/jmockit-1.40-sources.jar">
     162                <attributes>
     163                        <attribute name="test" value="true"/>
     164                </attributes>
     165        </classpathentry>
    161166        <classpathentry kind="output" path="bin"/>
    162167</classpath>
  • trunk/.travis.yml

    r13240 r14052  
    11language: java
    2 os:
    3   - linux
    4   - osx
     2script: (eval "$ANT_INVOCATION $(test $TRAVIS_JDK_VERSION = openjdk8 && echo -DnoJavaFX=true) test")
     3os: linux
     4dist: trusty
     5env:
     6  - ANT_INVOCATION="xvfb-run ant -Dtest.headless=false"
     7  - ANT_INVOCATION="ant -Dtest.headless=true"
     8jdk:
     9  - oraclejdk9
     10  - oraclejdk8
     11  - openjdk8
    512matrix:
    613  include:
    7     - os: linux
    8       dist: trusty
    9       sudo: required
    10       jdk:
    11         - oraclejdk9
    12         - oraclejdk8
    13         - openjdk8
    14     - os: osx
    15       osx_image: xcode9.2
     14  - os: osx
     15    osx_image: xcode9.2
     16    jdk: ~
     17    env: ANT_INVOCATION="ant -Dtest.headless=true"
    1618before_install:
    1719  - >
  • trunk/build.xml

    r14033 r14052  
    4343        <property name="dist-optimized.jar" location="${dist.dir}/josm-custom-optimized.jar"/>
    4444        <property name="java.lang.version" value="1.8" />
     45        <property name="test.headless" value="true" />
    4546        <property name="jacoco.includes" value="org.openstreetmap.josm.*" />
    4647        <property name="jacoco.inclbootstrapclasses" value="false" />
     
    501502                <junit printsummary="yes" fork="true" forkmode="once">
    502503                    <jvmarg value="-Dfile.encoding=UTF-8"/>
     504                    <jvmarg value="-javaagent:${test.dir}/lib/jmockit-1.40.jar"/>
    503505                    <jvmarg value="--add-modules" if:set="isJava9" unless:set="isJava11" />
    504506                    <jvmarg value="java.activation,java.se.ee" if:set="isJava9" unless:set="isJava11" />
     
    525527                    <sysproperty key="josm.home" value="${test.dir}/config/@{testfamily}-josm.home"/>
    526528                    <sysproperty key="josm.test.data" value="${test.dir}/data"/>
    527                     <sysproperty key="java.awt.headless" value="true"/>
     529                    <sysproperty key="java.awt.headless" value="${test.headless}"/>
    528530                    <sysproperty key="glass.platform" value="Monocle"/>
    529531                    <sysproperty key="monocle.platform" value="Headless"/>
  • trunk/src/org/openstreetmap/josm/data/preferences/JosmBaseDirectories.java

    r13776 r14052  
    155155        return cacheDir;
    156156    }
     157
     158    /**
     159     * Clears any previously calculated values used for {@link #getPreferencesDirectory(boolean)},
     160     * {@link #getCacheDirectory(boolean)} or {@link #getUserDataDirectory(boolean)}. Useful for tests.
     161     * @since 14052
     162     */
     163    public void clearMemos() {
     164        this.preferencesDir = null;
     165        this.cacheDir = null;
     166        this.userdataDir = null;
     167    }
    157168}
  • trunk/src/org/openstreetmap/josm/gui/ConditionalOptionPaneUtil.java

    r12846 r14052  
    265265     *
    266266     */
    267     static class MessagePanel extends JPanel {
     267    public static class MessagePanel extends JPanel {
    268268        private final JRadioButton cbShowPermanentDialog = new JRadioButton(NotShowAgain.PERMANENT.getLabel());
    269269        private final JRadioButton cbShowSessionDialog = new JRadioButton(NotShowAgain.SESSION.getLabel());
  • trunk/src/org/openstreetmap/josm/gui/MainApplication.java

    r13963 r14052  
    488488    @Override
    489489    protected void shutdown() {
    490         if (!GraphicsEnvironment.isHeadless()) {
    491             try {
    492                 worker.shutdown();
    493             } catch (SecurityException e) {
    494                 Logging.log(Logging.LEVEL_ERROR, "Unable to shutdown worker", e);
    495             }
    496             JCSCacheManager.shutdown();
    497         }
     490        try {
     491            worker.shutdown();
     492        } catch (SecurityException e) {
     493            Logging.log(Logging.LEVEL_ERROR, "Unable to shutdown worker", e);
     494        }
     495        JCSCacheManager.shutdown();
     496
    498497        if (mainFrame != null) {
    499498            mainFrame.storeState();
     
    505504        layerManager.resetState();
    506505        super.shutdown();
    507         if (!GraphicsEnvironment.isHeadless()) {
    508             try {
    509                 worker.shutdownNow();
    510             } catch (SecurityException e) {
    511                 Logging.log(Logging.LEVEL_ERROR, "Unable to shutdown worker", e);
    512             }
     506
     507        try {
     508            // in case the current task still hasn't finished
     509            worker.shutdownNow();
     510        } catch (SecurityException e) {
     511            Logging.log(Logging.LEVEL_ERROR, "Unable to shutdown worker", e);
    513512        }
    514513    }
  • trunk/src/org/openstreetmap/josm/gui/MapViewState.java

    r13387 r14052  
    33
    44import java.awt.Container;
    5 import java.awt.GraphicsEnvironment;
    65import java.awt.Point;
    76import java.awt.geom.AffineTransform;
     
    146145
    147146    private static Point findTopLeftOnScreen(JComponent position) {
    148         if (GraphicsEnvironment.isHeadless()) {
    149             // in our imaginary universe the window is always (10, 10) from the top left of the screen
    150             Point topLeftInWindow = findTopLeftInWindow(position);
    151             return new Point(topLeftInWindow.x + 10, topLeftInWindow.y + 10);
    152         } else {
    153             try {
    154                 return position.getLocationOnScreen();
    155             } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) {
    156                 throw BugReport.intercept(e).put("position", position).put("parent", position::getParent);
    157             }
     147        try {
     148            return position.getLocationOnScreen();
     149        } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) {
     150            throw BugReport.intercept(e).put("position", position).put("parent", position::getParent);
    158151        }
    159152    }
  • trunk/src/org/openstreetmap/josm/gui/NavigatableComponent.java

    r13868 r14052  
    33
    44import java.awt.Cursor;
    5 import java.awt.GraphicsEnvironment;
    65import java.awt.Point;
    76import java.awt.Rectangle;
     
    326325
    327326    protected boolean isVisibleOnScreen() {
    328         return GraphicsEnvironment.isHeadless() || (
    329             SwingUtilities.getWindowAncestor(this) != null && isShowing()
    330         );
     327        return SwingUtilities.getWindowAncestor(this) != null && isShowing();
    331328    }
    332329
  • trunk/src/org/openstreetmap/josm/gui/io/AsynchronousUploadPrimitivesTask.java

    r13654 r14052  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.awt.GraphicsEnvironment;
    76import java.util.Optional;
    87
     
    8685        synchronized (AsynchronousUploadPrimitivesTask.class) {
    8786            if (asynchronousUploadPrimitivesTask != null) {
    88                 if (!GraphicsEnvironment.isHeadless()) {
    89                     GuiHelper.runInEDTAndWait(() ->
    90                             JOptionPane.showMessageDialog(MainApplication.parent,
    91                                     tr("A background upload is already in progress. " +
    92                                             "Kindly wait for it to finish before uploading new changes")));
    93                 }
     87                GuiHelper.runInEDTAndWait(() ->
     88                        JOptionPane.showMessageDialog(MainApplication.parent,
     89                                tr("A background upload is already in progress. " +
     90                                        "Kindly wait for it to finish before uploading new changes")));
    9491                return Optional.empty();
    9592            } else {
  • trunk/src/org/openstreetmap/josm/gui/preferences/PreferenceTabbedPane.java

    r13431 r14052  
    2626import javax.swing.JScrollPane;
    2727import javax.swing.JTabbedPane;
    28 import javax.swing.SwingUtilities;
    2928import javax.swing.event.ChangeEvent;
    3029import javax.swing.event.ChangeListener;
     
    6059import org.openstreetmap.josm.gui.preferences.validator.ValidatorTagCheckerRulesPreference;
    6160import org.openstreetmap.josm.gui.preferences.validator.ValidatorTestsPreference;
     61import org.openstreetmap.josm.gui.util.GuiHelper;
    6262import org.openstreetmap.josm.plugins.PluginDownloadTask;
    6363import org.openstreetmap.josm.plugins.PluginHandler;
     
    175175            }
    176176
    177             Main.parent.repaint();
     177            if (Main.parent != null) {
     178                Main.parent.repaint();
     179            }
    178180        }
    179181    }
     
    421423                // by the remaining "save preferences" activites run on the Swing EDT.
    422424                MainApplication.worker.submit(task);
    423                 MainApplication.worker.submit(() -> SwingUtilities.invokeLater(continuation));
     425                MainApplication.worker.submit(() -> GuiHelper.runInEDT(continuation));
    424426            } else {
    425427                // no need for asynchronous activities. Simply run the remaining "save preference"
  • trunk/src/org/openstreetmap/josm/gui/preferences/advanced/ExportProfileAction.java

    r12881 r14052  
    5656        }
    5757        if (keys.isEmpty()) {
    58             if (!GraphicsEnvironment.isHeadless()) {
    59                 JOptionPane.showMessageDialog(Main.parent,
    60                         tr("All the preferences of this group are default, nothing to save"), tr("Warning"), JOptionPane.WARNING_MESSAGE);
    61             }
     58            JOptionPane.showMessageDialog(Main.parent,
     59                    tr("All the preferences of this group are default, nothing to save"), tr("Warning"), JOptionPane.WARNING_MESSAGE);
    6260            return;
    6361        }
  • trunk/src/org/openstreetmap/josm/gui/preferences/advanced/PreferencesTable.java

    r12987 r14052  
    88import java.awt.Component;
    99import java.awt.Font;
    10 import java.awt.GraphicsEnvironment;
    1110import java.awt.GridBagLayout;
    1211import java.awt.event.MouseAdapter;
     
    9695    public boolean editPreference(final JComponent gui) {
    9796        if (getSelectedRowCount() != 1) {
    98             if (!GraphicsEnvironment.isHeadless()) {
    99                 JOptionPane.showMessageDialog(
    100                         gui,
    101                         tr("Please select the row to edit."),
    102                         tr("Warning"),
    103                         JOptionPane.WARNING_MESSAGE
    104                         );
    105             }
     97            JOptionPane.showMessageDialog(
     98                    gui,
     99                    tr("Please select the row to edit."),
     100                    tr("Warning"),
     101                    JOptionPane.WARNING_MESSAGE
     102                    );
    106103            return false;
    107104        }
     
    197194        PrefEntry pe = null;
    198195        boolean ok = false;
    199         if (!GraphicsEnvironment.isHeadless() && askAddSetting(gui, p)) {
     196        if (askAddSetting(gui, p)) {
    200197            if (rbString.isSelected()) {
    201198                StringSetting sSetting = new StringSetting(null);
     
    282279    public void resetPreferences(final JComponent gui) {
    283280        if (getSelectedRowCount() == 0) {
    284             if (!GraphicsEnvironment.isHeadless()) {
    285                 JOptionPane.showMessageDialog(
    286                         gui,
    287                         tr("Please select the row to delete."),
    288                         tr("Warning"),
    289                         JOptionPane.WARNING_MESSAGE
    290                         );
    291             }
     281            JOptionPane.showMessageDialog(
     282                    gui,
     283                    tr("Please select the row to delete."),
     284                    tr("Warning"),
     285                    JOptionPane.WARNING_MESSAGE
     286                    );
    292287            return;
    293288        }
  • trunk/src/org/openstreetmap/josm/gui/preferences/plugin/PluginPreference.java

    r13842 r14052  
    77import java.awt.BorderLayout;
    88import java.awt.Component;
    9 import java.awt.GraphicsEnvironment;
    109import java.awt.GridBagConstraints;
    1110import java.awt.GridBagLayout;
     
    159158        }
    160159        sb.append("</html>");
    161         if (!GraphicsEnvironment.isHeadless()) {
    162             GuiHelper.runInEDTAndWait(() -> HelpAwareOptionPane.showOptionDialog(
    163                     parent,
    164                     sb.toString(),
    165                     tr("Update plugins"),
    166                     !failed.isEmpty() ? JOptionPane.WARNING_MESSAGE : JOptionPane.INFORMATION_MESSAGE,
    167                             HelpUtil.ht("/Preferences/Plugins")
    168                     ));
    169         }
     160        GuiHelper.runInEDTAndWait(() -> HelpAwareOptionPane.showOptionDialog(
     161                parent,
     162                sb.toString(),
     163                tr("Update plugins"),
     164                !failed.isEmpty() ? JOptionPane.WARNING_MESSAGE : JOptionPane.INFORMATION_MESSAGE,
     165                        HelpUtil.ht("/Preferences/Plugins")
     166                ));
    170167    }
    171168
     
    212209    }
    213210
     211    private static Component addButton(JPanel pnl, JButton button, String buttonName) {
     212        button.setName(buttonName);
     213        return pnl.add(button);
     214    }
     215
    214216    private JPanel buildActionPanel() {
    215217        JPanel pnl = new JPanel(new GridLayout(1, 4));
    216218
    217         pnl.add(new JButton(new DownloadAvailablePluginsAction()));
    218         pnl.add(new JButton(new UpdateSelectedPluginsAction()));
    219         ExpertToggleAction.addVisibilitySwitcher(pnl.add(new JButton(new SelectByListAction())));
    220         ExpertToggleAction.addVisibilitySwitcher(pnl.add(new JButton(new ConfigureSitesAction())));
     219        // assign some component names to these as we go to aid testing
     220        addButton(pnl, new JButton(new DownloadAvailablePluginsAction()), "downloadListButton");
     221        addButton(pnl, new JButton(new UpdateSelectedPluginsAction()), "updatePluginsButton");
     222        ExpertToggleAction.addVisibilitySwitcher(addButton(pnl, new JButton(new SelectByListAction()), "loadFromListButton"));
     223        ExpertToggleAction.addVisibilitySwitcher(addButton(pnl, new JButton(new ConfigureSitesAction()), "configureSitesButton"));
    221224        return pnl;
    222225    }
  • trunk/src/org/openstreetmap/josm/gui/progress/swing/ProgressMonitorExecutor.java

    r12675 r14052  
    22package org.openstreetmap.josm.gui.progress.swing;
    33
     4import java.util.concurrent.CancellationException;
     5import java.util.concurrent.ExecutionException;
     6import java.util.concurrent.Future;
    47import java.util.concurrent.LinkedBlockingQueue;
    58import java.util.concurrent.ThreadPoolExecutor;
    69import java.util.concurrent.TimeUnit;
    710
     11import org.openstreetmap.josm.tools.Logging;
    812import org.openstreetmap.josm.tools.Utils;
    913
     
    3741    }
    3842
     43    @Override
     44    public void afterExecute(final Runnable r, Throwable t) {
     45        // largely as proposed by JDK8 docs
     46        super.afterExecute(r, t);
     47        if (t == null && r instanceof Future<?>) {
     48            try {
     49                ((Future<?>) r).get();
     50            } catch (CancellationException cancellationException) {
     51                t = cancellationException;
     52            } catch (ExecutionException executionException) {
     53                t = executionException.getCause();
     54            } catch (InterruptedException interruptedException) {
     55                Thread.currentThread().interrupt(); // ignore/reset
     56            }
     57        }
     58        if (t != null) {
     59            Logging.error("Thread {0} raised {1}", Thread.currentThread().getName(), t);
     60        }
     61    }
    3962}
  • trunk/src/org/openstreetmap/josm/gui/util/GuiHelper.java

    r13493 r14052  
    202202    }
    203203
     204    private static void handleEDTException(Throwable t) {
     205        Logging.logWithStackTrace(Logging.LEVEL_ERROR, t, "Exception raised in EDT");
     206    }
     207
    204208    /**
    205209     * Executes synchronously a runnable in
     
    215219                SwingUtilities.invokeAndWait(task);
    216220            } catch (InterruptedException | InvocationTargetException e) {
    217                 Logging.error(e);
     221                handleEDTException(e);
    218222            }
    219223        }
     
    256260                return callable.call();
    257261            } catch (Exception e) { // NOPMD
    258                 Logging.error(e);
     262                handleEDTException(e);
    259263                return null;
    260264            }
     
    265269                return task.get();
    266270            } catch (InterruptedException | ExecutionException e) {
    267                 Logging.error(e);
     271                handleEDTException(e);
    268272                return null;
    269273            }
  • trunk/src/org/openstreetmap/josm/tools/Logging.java

    r13647 r14052  
    5151    private static final RememberWarningHandler WARNINGS = new RememberWarningHandler();
    5252
     53    /**
     54     * A {@link ConsoleHandler} with a couple of extra features, allowing it to be targeted at an
     55     * an arbitrary {@link OutputStream} which it can be asked to reaquire the reference for on demand
     56     * through {@link #reacquireOutputStream()}. It can also prevent a LogRecord's output if a
     57     * specified {@code prioritizedHandler} would have outputted it.
     58     * @since 14052
     59     */
     60    public static class ReacquiringConsoleHandler extends ConsoleHandler {
     61        private final Supplier<OutputStream> outputStreamSupplier;
     62        private final Handler prioritizedHandler;
     63        private OutputStream outputStreamMemo;
     64
     65        /**
     66        * Construct a new {@link ReacquiringConsoleHandler}.
     67        * @param outputStreamSupplier A {@link Supplier} which will return the desired
     68        *   {@link OutputStream} for this handler when called. Particularly useful if you happen to be
     69        *   using a test framework which will switch out references to the stderr/stdout streams with
     70        *   new dummy ones from time to time.
     71        * @param prioritizedHandler If non-null, will suppress output of any log records which pass this
     72        *   handler's {@code Handler#isLoggable(LogRecord)} method.
     73        */
     74        public ReacquiringConsoleHandler(
     75            final Supplier<OutputStream> outputStreamSupplier,
     76            final Handler prioritizedHandler
     77        ) {
     78            this.outputStreamSupplier = outputStreamSupplier;
     79            this.prioritizedHandler = prioritizedHandler;
     80
     81            this.reacquireOutputStream();
     82        }
     83
     84        /**
     85         * Set output stream to one acquired from calling outputStreamSupplier
     86         */
     87        public void reacquireOutputStream() {
     88            final OutputStream reacquiredStream = this.outputStreamSupplier.get();
     89
     90            // only bother calling setOutputStream if it's actually different, as setOutputStream
     91            // has the nasty side effect of closing any previous output stream, which is certainly not
     92            // what we would want were the new stream the same one
     93            if (reacquiredStream != this.outputStreamMemo) {
     94                this.setOutputStream(reacquiredStream);
     95            }
     96        }
     97
     98        @Override
     99        public synchronized void setOutputStream(final OutputStream outputStream) {
     100            // this wouldn't be necessary if StreamHandler made it possible to see what the current
     101            // output stream is set to
     102            this.outputStreamMemo = outputStream;
     103            super.setOutputStream(outputStream);
     104        }
     105
     106        @Override
     107        public synchronized void publish(LogRecord record) {
     108            if (this.prioritizedHandler == null || !this.prioritizedHandler.isLoggable(record)) {
     109                super.publish(record);
     110            }
     111        }
     112    }
     113
    53114    static {
    54115        // We need to be sure java.locale.providers system property is initialized by JOSM, not by JRE
     
    62123        Utils.updateSystemProperty("java.util.logging.SimpleFormatter.format", "%1$tF %1$tT.%1$tL %4$s: %5$s%6$s%n");
    63124
    64         ConsoleHandler stderr = new ConsoleHandler();
     125        ConsoleHandler stderr = new ReacquiringConsoleHandler(() -> System.err, null);
    65126        LOGGER.addHandler(stderr);
    66127        try {
     
    70131        }
    71132
    72         ConsoleHandler stdout = new ConsoleHandler() {
    73             @Override
    74             protected synchronized void setOutputStream(OutputStream out) {
    75                 // overwrite output stream.
    76                 super.setOutputStream(System.out);
    77             }
    78 
    79             @Override
    80             public synchronized void publish(LogRecord record) {
    81                 if (!stderr.isLoggable(record)) {
    82                     super.publish(record);
    83                 }
    84             }
    85         };
     133        ConsoleHandler stdout = new ReacquiringConsoleHandler(() -> System.out, stderr);
    86134        LOGGER.addHandler(stdout);
    87135        try {
  • trunk/test/unit/org/openstreetmap/josm/TestUtils.java

    r13742 r14052  
    33
    44import static org.junit.Assert.assertEquals;
     5import static org.junit.Assert.assertArrayEquals;
     6import static org.junit.Assert.assertTrue;
    57import static org.junit.Assert.fail;
    68
     
    911import java.awt.Graphics2D;
    1012import java.io.File;
     13import java.io.FileInputStream;
    1114import java.io.IOException;
    1215import java.io.InputStream;
     
    2326import java.util.Comparator;
    2427import java.util.Objects;
     28import java.util.concurrent.ExecutionException;
     29import java.util.concurrent.ThreadPoolExecutor;
    2530import java.util.stream.Stream;
    2631
     
    3439import org.openstreetmap.josm.data.osm.RelationMember;
    3540import org.openstreetmap.josm.data.osm.Way;
     41import org.openstreetmap.josm.gui.MainApplication;
    3642import org.openstreetmap.josm.gui.progress.AbstractProgressMonitor;
    3743import org.openstreetmap.josm.gui.progress.CancelHandler;
    3844import org.openstreetmap.josm.gui.progress.ProgressMonitor;
    3945import org.openstreetmap.josm.gui.progress.ProgressTaskId;
     46import org.openstreetmap.josm.gui.util.GuiHelper;
    4047import org.openstreetmap.josm.io.Compression;
    4148import org.openstreetmap.josm.testutils.FakeGraphics;
     
    4552import com.github.tomakehurst.wiremock.WireMockServer;
    4653import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
     54
     55import com.google.common.io.ByteStreams;
    4756
    4857import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     
    429438        return getHTTPDate(Instant.ofEpochMilli(time));
    430439    }
     440
     441    /**
     442     * Throws AssertionError if contents of both files are not equal
     443     * @param fileA File A
     444     * @param fileB File B
     445     */
     446    public static void assertFileContentsEqual(final File fileA, final File fileB) {
     447        assertTrue(fileA.exists());
     448        assertTrue(fileA.canRead());
     449        assertTrue(fileB.exists());
     450        assertTrue(fileB.canRead());
     451        try {
     452            try (
     453                FileInputStream streamA = new FileInputStream(fileA);
     454                FileInputStream streamB = new FileInputStream(fileB);
     455            ) {
     456                assertArrayEquals(
     457                    ByteStreams.toByteArray(streamA),
     458                    ByteStreams.toByteArray(streamB)
     459                );
     460            }
     461        } catch (IOException e) {
     462            fail(e.toString());
     463        }
     464    }
     465
     466    /**
     467     * Waits until any asynchronous operations launched by the test on the EDT or worker threads have
     468     * (almost certainly) completed.
     469     */
     470    public static void syncEDTAndWorkerThreads() {
     471        boolean workerQueueEmpty = false;
     472        while (!workerQueueEmpty) {
     473            try {
     474                // once our own task(s) have made it to the front of their respective queue(s),
     475                // they're both executing at the same time and we know there aren't any outstanding
     476                // worker tasks, then presumably the only way there could be incomplete operations
     477                // is if the EDT had launched a deferred task to run on itself or perhaps set up a
     478                // swing timer - neither are particularly common patterns in JOSM (?)
     479                //
     480                // there shouldn't be a risk of creating a deadlock in doing this as there shouldn't
     481                // (...couldn't?) be EDT operations waiting on the results of a worker task.
     482                workerQueueEmpty = MainApplication.worker.submit(
     483                    () -> GuiHelper.runInEDTAndWaitAndReturn(
     484                        () -> ((ThreadPoolExecutor) MainApplication.worker).getQueue().isEmpty()
     485                    )
     486                ).get();
     487            } catch (InterruptedException | ExecutionException e) {
     488                // inconclusive - retry...
     489                workerQueueEmpty = false;
     490            }
     491        }
     492    }
    431493}
  • trunk/test/unit/org/openstreetmap/josm/actions/ExitActionTest.java

    r11101 r14052  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.actions;
     3
     4import static org.junit.Assert.assertTrue;
    35
    46import org.junit.Rule;
    57import org.junit.Test;
    68import org.junit.contrib.java.lang.system.ExpectedSystemExit;
     9import org.openstreetmap.josm.gui.MainApplication;
     10import org.openstreetmap.josm.gui.progress.swing.ProgressMonitorExecutor;
    711import org.openstreetmap.josm.testutils.JOSMTestRules;
     12import org.openstreetmap.josm.tools.ImageProvider;
     13
     14import mockit.Invocation;
     15import mockit.Mock;
     16import mockit.MockUp;
    817
    918import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     
    3342    public void testActionPerformed() {
    3443        exit.expectSystemExitWithStatus(0);
     44
     45        boolean[] workerShutdownCalled = {false};
     46        boolean[] workerShutdownNowCalled = {false};
     47        boolean[] imageProviderShutdownCalled = {false};
     48
     49        // critically we don't proceed into the actual implementation in any of these mock methods -
     50        // that would be quite annoying for tests following this one which were expecting to use any
     51        // of these
     52        new MockUp<ProgressMonitorExecutor>() {
     53            @Mock
     54            private void shutdown(Invocation invocation) {
     55                if (invocation.getInvokedInstance() == MainApplication.worker) {
     56                    workerShutdownCalled[0] = true;
     57                }
     58            }
     59
     60            @Mock
     61            private void shutdownNow(Invocation invocation) {
     62                if (invocation.getInvokedInstance() == MainApplication.worker) {
     63                    // regular shutdown should have been called first
     64                    assertTrue(workerShutdownCalled[0]);
     65                    workerShutdownNowCalled[0] = true;
     66                }
     67            }
     68        };
     69        new MockUp<ImageProvider>() {
     70            @Mock
     71            private void shutdown(Invocation invocation) {
     72                imageProviderShutdownCalled[0] = true;
     73            }
     74        };
     75
    3576        // No layer
     77
    3678        new ExitAction().actionPerformed(null);
     79
     80        assertTrue(workerShutdownCalled[0]);
     81        assertTrue(workerShutdownNowCalled[0]);
     82        assertTrue(imageProviderShutdownCalled[0]);
    3783    }
    3884}
  • trunk/test/unit/org/openstreetmap/josm/actions/downloadtasks/PluginDownloadTaskTest.java

    r13300 r14052  
    5656    @Test
    5757    public void testUpdatePluginValid() throws Exception {
    58         this.pluginPath = "plugin/dummy_plugin.jar";
     58        this.pluginPath = "plugin/dummy_plugin.v31772.jar";
    5959        this.mockHttp();
    6060
     
    7474
    7575        // get PluginInformation from jar file
    76         final PluginInformation pluginInformation = new PluginInformation(srcPluginFile);
     76        final PluginInformation pluginInformation = new PluginInformation(srcPluginFile, "dummy_plugin");
    7777        // ...and grafting on the downloadlink
    7878        pluginInformation.downloadlink = this.getRemoteFileUrl();
     
    8787        // the ".jar.new" file should have been deleted
    8888        assertFalse(pluginFileNew.exists());
    89         // the ".jar" file should still exist
    90         assertTrue(pluginFile.exists());
    91         try (
    92             FileInputStream pluginDirPluginStream = new FileInputStream(pluginFile);
    93             FileInputStream srcPluginStream = new FileInputStream(srcPluginFile);
    94         ) {
    95             // and its contents should equal those that were served to the task
    96             assertArrayEquals(
    97                 ByteStreams.toByteArray(pluginDirPluginStream),
    98                 ByteStreams.toByteArray(srcPluginStream)
    99             );
    100         }
     89        // the ".jar" file should still exist and its contents should equal those that were served to the task
     90        TestUtils.assertFileContentsEqual(pluginFile, srcPluginFile);
    10191    }
    10292
     
    140130        }
    141131
    142         // the ".jar.new" file should exist, even though invalid
    143         assertTrue(pluginFileNew.exists());
     132        // assert that the "corrupt" jar file made it through in tact
     133        TestUtils.assertFileContentsEqual(pluginFileNew, srcPluginFile);
    144134        // the ".jar" file should still exist
    145135        assertTrue(pluginFile.exists());
    146136        try (
    147             FileInputStream pluginDirPluginNewStream = new FileInputStream(pluginFileNew);
    148137            FileInputStream pluginDirPluginStream = new FileInputStream(pluginFile);
    149             FileInputStream srcPluginStream = new FileInputStream(srcPluginFile);
    150138        ) {
    151139            // the ".jar" file's contents should be as before
     
    154142                ByteStreams.toByteArray(pluginDirPluginStream)
    155143            );
    156             // just assert that the "corrupt" jar file made it through in tact
    157             assertArrayEquals(
    158                 ByteStreams.toByteArray(pluginDirPluginNewStream),
    159                 ByteStreams.toByteArray(srcPluginStream)
    160             );
    161144        }
    162145    }
  • trunk/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java

    r13181 r14052  
    33
    44import static java.util.concurrent.TimeUnit.MILLISECONDS;
     5import static org.openstreetmap.josm.tools.I18n.tr;
    56import static org.junit.Assert.assertEquals;
    67import static org.junit.Assert.assertFalse;
     
    1920
    2021import javax.swing.JMenuItem;
     22import javax.swing.JCheckBoxMenuItem;
    2123import javax.swing.JPopupMenu;
    2224
     
    2729import org.openstreetmap.josm.TestUtils;
    2830import org.openstreetmap.josm.data.Bounds;
     31import org.openstreetmap.josm.data.DataSource;
     32import org.openstreetmap.josm.data.osm.DataSet;
    2933import org.openstreetmap.josm.data.projection.Projections;
    3034import org.openstreetmap.josm.gui.MainApplication;
     
    3236import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
    3337import org.openstreetmap.josm.gui.bbox.SourceButton;
     38import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    3439import org.openstreetmap.josm.gui.layer.LayerManagerTest.TestLayer;
    3540import org.openstreetmap.josm.gui.util.GuiHelper;
     
    8792                break;
    8893            } else {
    89                 boolean equalText = ((JMenuItem) c).getText() == label;
     94                boolean equalText = ((JMenuItem) c).getText().equals(label);
    9095                boolean isSelected = ((JMenuItem) c).isSelected();
    9196                assertEquals(equalText, isSelected);
     
    297302
    298303        Map<Integer, String> paletteMap = ImmutableMap.<Integer, String>builder()
    299             .put(0xffffffff, "w")
    300             .put(0xff000000, "b")
    301             .put(0xfff0d1d1, "p")
     304            .put(0xffffffff, "w")  // white
     305            .put(0xff000000, "b")  // black
     306            .put(0xfff0d1d1, "p")  // pink
    302307            .build();
    303308
     
    385390        );
    386391    }
     392
     393    protected JCheckBoxMenuItem getShowDownloadedAreaMenuItem() {
     394        JPopupMenu menu = this.sourceButton.getPopupMenu();
     395        boolean afterSeparator = false;
     396        for (Component c: menu.getComponents()) {
     397            if (JPopupMenu.Separator.class.isInstance(c)) {
     398                assertFalse("More than one separator before target item", afterSeparator);
     399                afterSeparator = true;
     400            } else if (((JMenuItem) c).getText().equals(tr("Show downloaded area"))) {
     401                assertTrue("Separator not found before target item", afterSeparator);
     402                assertTrue("Target item doesn't appear to be a JCheckBoxMenuItem", JCheckBoxMenuItem.class.isInstance(c));
     403                return (JCheckBoxMenuItem) c;
     404            }
     405        }
     406        fail("'Show downloaded area' menu item not found");
     407        return null;
     408    }
     409
     410    /**
     411     * test downloaded area is shown shaded
     412     * @throws Exception if any error occurs
     413     */
     414    @Test
     415    public void testShowDownloadedArea() throws Exception {
     416        Main.pref.put("slippy_map_chooser.mapstyle", "Green Tiles");
     417        Main.pref.putBoolean("slippy_map_chooser.show_downloaded_area", false);
     418
     419        DataSet dataSet = new DataSet();
     420        dataSet.addDataSource(new DataSource(new Bounds(51.725, -0.0209, 51.746, 0.0162), "Somewhere"));
     421
     422        OsmDataLayer dataLayer = new OsmDataLayer(
     423            dataSet,
     424            "Test Layer 123",
     425            null
     426        );
     427        MainApplication.getLayerManager().addLayer(dataLayer);
     428        MainApplication.getLayerManager().setActiveLayer(dataLayer);
     429
     430        MapView mapView = MainApplication.getMap().mapView;
     431        GuiHelper.runInEDTAndWaitWithException(() -> {
     432            mapView.setVisible(true);
     433            mapView.addNotify();
     434            mapView.doLayout();
     435            mapView.setBounds(0, 0, 500, 500);
     436        });
     437
     438        this.setUpMiniMap();
     439
     440        // assert "show downloaded areas" checkbox is unchecked
     441        assertFalse(this.getShowDownloadedAreaMenuItem().isSelected());
     442
     443        // we won't end up with exactly this viewport as it doesn't *precisely* match the aspect ratio
     444        mapView.zoomTo(new Bounds(51.732, -0.0269, 51.753, 0.0102));
     445
     446        // an initial paint operation is required to trigger the tile fetches
     447        this.paintSlippyMap();
     448
     449        Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
     450
     451        this.paintSlippyMap();
     452
     453        Map<Integer, String> paletteMap = ImmutableMap.<Integer, String>builder()
     454            .put(0xff00ff00, "g")  // green
     455            .put(0xff000000, "b")  // black
     456            .put(0xff8ad16b, "v")  // viewport marker inner (pink+green mix)
     457            .put(0xff00df00, "d")  // (shaded green)
     458            .put(0xff8ac46b, "q")  // (shaded pink+green mix)
     459            .build();
     460
     461        // assert downloaded areas are not drawn
     462        ImagePatternMatching.rowMatch(
     463            paintedSlippyMap,
     464            paintedSlippyMap.getHeight()/2,
     465            paletteMap,
     466            "^g+bv+bg+$",
     467            true
     468        );
     469        ImagePatternMatching.columnMatch(
     470            paintedSlippyMap,
     471            paintedSlippyMap.getWidth()/2,
     472            paletteMap,
     473            "^g+bv+bg+$",
     474            true
     475        );
     476
     477        // enable "show downloaded areas"
     478        GuiHelper.runInEDTAndWaitWithException(() -> this.getShowDownloadedAreaMenuItem().doClick());
     479        assertTrue(this.getShowDownloadedAreaMenuItem().isSelected());
     480
     481        // assert downloaded areas are drawn
     482        this.paintSlippyMap();
     483
     484        ImagePatternMatching.rowMatch(
     485            paintedSlippyMap,
     486            paintedSlippyMap.getHeight()/2,
     487            paletteMap,
     488            "^d+bq+v+bg+d+$",
     489            true
     490        );
     491        ImagePatternMatching.columnMatch(
     492            paintedSlippyMap,
     493            paintedSlippyMap.getWidth()/2,
     494            paletteMap,
     495            "^d+bq+v+bg+d+$",
     496            true
     497        );
     498
     499        // also assert the leftmost column doesn't (yet) have any downloaded area marks (i.e. fully shaded)
     500        ImagePatternMatching.columnMatch(
     501            paintedSlippyMap,
     502            0,
     503            paletteMap,
     504            "^d+$",
     505            true
     506        );
     507
     508        // add another downloaded area, going off the left of the widget
     509        dataSet.addDataSource(new DataSource(new Bounds(51.745, -1., 51.765, 0.0162), "Somewhere else"));
     510        // and redraw
     511        this.paintSlippyMap();
     512
     513        // the middle row should be as before
     514        ImagePatternMatching.rowMatch(
     515            paintedSlippyMap,
     516            paintedSlippyMap.getHeight()/2,
     517            paletteMap,
     518            "^d+bq+v+bg+d+$",
     519            true
     520        );
     521        // the middle column should have its unshaded region extended beyond the viewport marker
     522        ImagePatternMatching.columnMatch(
     523            paintedSlippyMap,
     524            paintedSlippyMap.getWidth()/2,
     525            paletteMap,
     526            "^d+g+bv+bg+d+$",
     527            true
     528        );
     529        // but the leftmost column should now have an unshaded mark
     530        ImagePatternMatching.columnMatch(
     531            paintedSlippyMap,
     532            0,
     533            paletteMap,
     534            "^d+g+d+$",
     535            true
     536        );
     537        // and the rightmost column should be untouched
     538        ImagePatternMatching.columnMatch(
     539            paintedSlippyMap,
     540            paintedSlippyMap.getWidth()-1,
     541            paletteMap,
     542            "^d+$",
     543            true
     544        );
     545
     546        // and now if we pan to the left (in EastNorth units)
     547        mapView.zoomTo(mapView.getCenter().add(-5000., 0.));
     548        // and redraw
     549        this.paintSlippyMap();
     550
     551        // the middle row should have its unshaded region outside the viewport marker
     552        ImagePatternMatching.rowMatch(
     553            paintedSlippyMap,
     554            paintedSlippyMap.getHeight()/2,
     555            paletteMap,
     556            "^d+bq+bd+g+d*$",
     557            true
     558        );
     559        // the middle column should have a shaded region inside the viewport marker
     560        ImagePatternMatching.columnMatch(
     561            paintedSlippyMap,
     562            paintedSlippyMap.getWidth()/2,
     563            paletteMap,
     564            "^d+g+bv+q+bd+$",
     565            true
     566        );
     567    }
     568
     569    /**
     570     * test display of downloaded area follows active layer switching
     571     * @throws Exception if any error occurs
     572     */
     573    @Test
     574    public void testShowDownloadedAreaLayerSwitching() throws Exception {
     575        Main.pref.put("slippy_map_chooser.mapstyle", "Green Tiles");
     576        Main.pref.putBoolean("slippy_map_chooser.show_downloaded_area", true);
     577
     578        DataSet dataSetA = new DataSet();
     579        // dataSetA has a long thin horizontal downloaded area (extending off the left & right of the map)
     580        dataSetA.addDataSource(new DataSource(new Bounds(-18., -61.02, -15., -60.98), "Elsewhere"));
     581
     582        OsmDataLayer dataLayerA = new OsmDataLayer(
     583            dataSetA,
     584            "Test Layer A",
     585            null
     586        );
     587        MainApplication.getLayerManager().addLayer(dataLayerA);
     588
     589        DataSet dataSetB = new DataSet();
     590        // dataSetB has a long thin vertical downloaded area (extending off the top & bottom of the map)
     591        dataSetB.addDataSource(new DataSource(new Bounds(-16.38, -62., -16.34, -60.), "Nowhere"));
     592
     593        OsmDataLayer dataLayerB = new OsmDataLayer(
     594            dataSetB,
     595            "Test Layer B",
     596            null
     597        );
     598        MainApplication.getLayerManager().addLayer(dataLayerB);
     599
     600        MainApplication.getLayerManager().setActiveLayer(dataLayerB);
     601
     602        MapView mapView = MainApplication.getMap().mapView;
     603        GuiHelper.runInEDTAndWaitWithException(() -> {
     604            mapView.setVisible(true);
     605            mapView.addNotify();
     606            mapView.doLayout();
     607            mapView.setBounds(0, 0, 400, 400);
     608        });
     609
     610        this.setUpMiniMap();
     611
     612        // assert "show downloaded areas" checkbox is checked
     613        assertTrue(this.getShowDownloadedAreaMenuItem().isSelected());
     614
     615        // again, we won't end up with exactly this viewport as it doesn't *precisely* match the aspect ratio
     616        mapView.zoomTo(new Bounds(-16.423, -61.076, -16.299, -60.932));
     617
     618        // an initial paint operation is required to trigger the tile fetches
     619        this.paintSlippyMap();
     620
     621        Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
     622
     623        this.paintSlippyMap();
     624
     625        Map<Integer, String> paletteMap = ImmutableMap.<Integer, String>builder()
     626            .put(0xff00ff00, "g")  // green
     627            .put(0xff000000, "b")  // black
     628            .put(0xff8ad16b, "v")  // viewport marker inner (pink+green mix)
     629            .put(0xff00df00, "d")  // (shaded green)
     630            .put(0xff8ac46b, "q")  // (shaded pink+green mix)
     631            .build();
     632
     633        // the middle row should be entirely unshaded
     634        ImagePatternMatching.rowMatch(
     635            paintedSlippyMap,
     636            paintedSlippyMap.getHeight()/2,
     637            paletteMap,
     638            "^g+bv+bg+$",
     639            true
     640        );
     641        // the middle column should have an unshaded band within the viewport marker
     642        Matcher centerMatcher = ImagePatternMatching.columnMatch(
     643            paintedSlippyMap,
     644            paintedSlippyMap.getWidth()/2,
     645            paletteMap,
     646            "^(d+bq+)(v+)(q+bd+)$",
     647            true
     648        );
     649        // the leftmost and rightmost columns should have an unshaded band
     650        Matcher leftMatcher = ImagePatternMatching.columnMatch(
     651            paintedSlippyMap,
     652            0,
     653            paletteMap,
     654            "^(d+)(g+)(d+)$",
     655            true
     656        );
     657        Matcher rightMatcher = ImagePatternMatching.columnMatch(
     658            paintedSlippyMap,
     659            paintedSlippyMap.getWidth()-1,
     660            paletteMap,
     661            "^(d+)(g+)(d+)$",
     662            true
     663        );
     664        // the three columns should have the unshaded band in the same place
     665        assertEquals(centerMatcher.group(1).length(), leftMatcher.group(1).length());
     666        assertEquals(centerMatcher.group(1).length(), rightMatcher.group(1).length());
     667        assertEquals(centerMatcher.group(2).length(), leftMatcher.group(2).length());
     668        assertEquals(centerMatcher.group(2).length(), rightMatcher.group(2).length());
     669
     670        // switch active layer
     671        MainApplication.getLayerManager().setActiveLayer(dataLayerA);
     672        this.paintSlippyMap();
     673
     674        // the middle column should be entirely unshaded
     675        ImagePatternMatching.columnMatch(
     676            paintedSlippyMap,
     677            paintedSlippyMap.getWidth()/2,
     678            paletteMap,
     679            "^g+bv+bg+$",
     680            true
     681        );
     682        // the middle row should have an unshaded band within the viewport marker
     683        centerMatcher = ImagePatternMatching.rowMatch(
     684            paintedSlippyMap,
     685            paintedSlippyMap.getHeight()/2,
     686            paletteMap,
     687            "^(d+bq+)(v+)(q+bd+)$",
     688            true
     689        );
     690        // the topmost and bottommost rows should have an unshaded band
     691        Matcher topMatcher = ImagePatternMatching.rowMatch(
     692            paintedSlippyMap,
     693            0,
     694            paletteMap,
     695            "^(d+)(g+)(d+)$",
     696            true
     697        );
     698        Matcher BottomMatcher = ImagePatternMatching.rowMatch(
     699            paintedSlippyMap,
     700            paintedSlippyMap.getHeight()-1,
     701            paletteMap,
     702            "^(d+)(g+)(d+)$",
     703            true
     704        );
     705        // the three rows should have the unshaded band in the same place
     706        assertEquals(centerMatcher.group(1).length(), topMatcher.group(1).length());
     707        assertEquals(centerMatcher.group(1).length(), BottomMatcher.group(1).length());
     708        assertEquals(centerMatcher.group(2).length(), topMatcher.group(2).length());
     709        assertEquals(centerMatcher.group(2).length(), BottomMatcher.group(2).length());
     710
     711        // deleting dataLayerA should hopefully switch our active layer back to dataLayerB
     712        MainApplication.getLayerManager().removeLayer(dataLayerA);
     713        this.paintSlippyMap();
     714
     715        // now we're really just repeating the same assertions we made originally when dataLayerB was active
     716        // the middle row should be entirely unshaded
     717        ImagePatternMatching.rowMatch(
     718            paintedSlippyMap,
     719            paintedSlippyMap.getHeight()/2,
     720            paletteMap,
     721            "^g+bv+bg+$",
     722            true
     723        );
     724        // the middle column should have an unshaded band within the viewport marker
     725        centerMatcher = ImagePatternMatching.columnMatch(
     726            paintedSlippyMap,
     727            paintedSlippyMap.getWidth()/2,
     728            paletteMap,
     729            "^(d+bq+)(v+)(q+bd+)$",
     730            true
     731        );
     732        // the leftmost and rightmost columns should have an unshaded band
     733        leftMatcher = ImagePatternMatching.columnMatch(
     734            paintedSlippyMap,
     735            0,
     736            paletteMap,
     737            "^(d+)(g+)(d+)$",
     738            true
     739        );
     740        rightMatcher = ImagePatternMatching.columnMatch(
     741            paintedSlippyMap,
     742            paintedSlippyMap.getWidth()-1,
     743            paletteMap,
     744            "^(d+)(g+)(d+)$",
     745            true
     746        );
     747        // the three columns should have the unshaded band in the same place
     748        assertEquals(centerMatcher.group(1).length(), leftMatcher.group(1).length());
     749        assertEquals(centerMatcher.group(1).length(), rightMatcher.group(1).length());
     750        assertEquals(centerMatcher.group(2).length(), leftMatcher.group(2).length());
     751        assertEquals(centerMatcher.group(2).length(), rightMatcher.group(2).length());
     752
     753        // but now if we expand its downloaded area to cover most of the southern hemisphere...
     754        dataSetB.addDataSource(new DataSource(new Bounds(-75., -100., 0., 100.), "Everywhere"));
     755        this.paintSlippyMap();
     756
     757        // we should see it all as unshaded.
     758        ImagePatternMatching.rowMatch(
     759            paintedSlippyMap,
     760            0,
     761            paletteMap,
     762            "^g+$",
     763            true
     764        );
     765        ImagePatternMatching.rowMatch(
     766            paintedSlippyMap,
     767            paintedSlippyMap.getHeight()/2,
     768            paletteMap,
     769            "^g+bv+bg+$",
     770            true
     771        );
     772        ImagePatternMatching.rowMatch(
     773            paintedSlippyMap,
     774            paintedSlippyMap.getHeight()-1,
     775            paletteMap,
     776            "^g+$",
     777            true
     778        );
     779        ImagePatternMatching.columnMatch(
     780            paintedSlippyMap,
     781            0,
     782            paletteMap,
     783            "^g+$",
     784            true
     785        );
     786        ImagePatternMatching.columnMatch(
     787            paintedSlippyMap,
     788            paintedSlippyMap.getWidth()/2,
     789            paletteMap,
     790            "^g+bv+bg+$",
     791            true
     792        );
     793        ImagePatternMatching.columnMatch(
     794            paintedSlippyMap,
     795            paintedSlippyMap.getWidth()-1,
     796            paletteMap,
     797            "^g+$",
     798            true
     799        );
     800    }
    387801}
  • trunk/test/unit/org/openstreetmap/josm/gui/io/AsynchronousUploadPrimitivesTaskTest.java

    r13219 r14052  
    33
    44import java.util.Optional;
     5
     6import javax.swing.JOptionPane;
    57
    68import org.junit.After;
     
    1820import org.openstreetmap.josm.io.UploadStrategySpecification;
    1921import org.openstreetmap.josm.testutils.JOSMTestRules;
     22import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
     23
     24import com.google.common.collect.ImmutableMap;
    2025
    2126import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     
    3742    @Rule
    3843    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
    39     public JOSMTestRules test = new JOSMTestRules();
     44    public JOSMTestRules test = new JOSMTestRules().assertionsInEDT();
    4045
     46    /**
     47     * Bootstrap.
     48     */
    4149    @Before
    4250    public void bootStrap() {
     51        new JOptionPaneSimpleMocker(ImmutableMap.of(
     52            "A background upload is already in progress. Kindly wait for it to finish before uploading new changes", JOptionPane.OK_OPTION
     53        ));
     54
    4355        DataSet dataSet = new DataSet();
    4456        Node node1 = new Node();
     
    6072    }
    6173
     74    /**
     75     * Tear down.
     76     */
    6277    @After
    6378    public void tearDown() {
     
    7085    }
    7186
     87    /**
     88     * Test single upload instance.
     89     */
    7290    @Test
    7391    public void testSingleUploadInstance() {
  • trunk/test/unit/org/openstreetmap/josm/gui/preferences/advanced/ExportProfileActionTest.java

    r10378 r14052  
    22package org.openstreetmap.josm.gui.preferences.advanced;
    33
    4 import org.junit.BeforeClass;
     4import javax.swing.JOptionPane;
     5
     6import org.junit.Rule;
    57import org.junit.Test;
    6 import org.openstreetmap.josm.JOSMFixture;
    78import org.openstreetmap.josm.Main;
     9import org.openstreetmap.josm.testutils.JOSMTestRules;
     10import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
     11
     12import com.google.common.collect.ImmutableMap;
     13
     14import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
    815
    916/**
     
    1118 */
    1219public class ExportProfileActionTest {
    13 
    1420    /**
    15      * Setup test.
     21     * Setup tests
    1622     */
    17     @BeforeClass
    18     public static void setUpBeforeClass() {
    19         JOSMFixture.createUnitTestFixture().init();
    20     }
     23    @Rule
     24    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     25    public JOSMTestRules test = new JOSMTestRules().preferences().assertionsInEDT();
    2126
    2227    /**
     
    2530    @Test
    2631    public void testAction() {
     32        new JOptionPaneSimpleMocker(ImmutableMap.of(
     33            "All the preferences of this group are default, nothing to save", JOptionPane.OK_OPTION
     34        ));
    2735        new ExportProfileAction(Main.pref, "foo", "bar").actionPerformed(null);
    2836        new ExportProfileAction(Main.pref, "expert", "expert").actionPerformed(null);
  • trunk/test/unit/org/openstreetmap/josm/gui/preferences/advanced/PreferencesTableTest.java

    r12884 r14052  
    99import java.util.Arrays;
    1010
    11 import org.junit.BeforeClass;
     11import javax.swing.JOptionPane;
     12
     13import org.junit.Rule;
    1214import org.junit.Test;
    13 import org.openstreetmap.josm.JOSMFixture;
     15import org.openstreetmap.josm.gui.ExtendedDialog;
     16import org.openstreetmap.josm.gui.preferences.advanced.PreferencesTable.AllSettingsTableModel;
    1417import org.openstreetmap.josm.spi.preferences.StringSetting;
    15 import org.openstreetmap.josm.gui.preferences.advanced.PreferencesTable.AllSettingsTableModel;
     18import org.openstreetmap.josm.testutils.JOSMTestRules;
     19import org.openstreetmap.josm.testutils.mockers.ExtendedDialogMocker;
     20import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
     21
     22import com.google.common.collect.ImmutableMap;
     23
     24import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
    1625
    1726/**
     
    1928 */
    2029public class PreferencesTableTest {
    21 
    2230    /**
    23      * Setup test.
     31     * Setup tests
    2432     */
    25     @BeforeClass
    26     public static void setUpBeforeClass() {
    27         JOSMFixture.createUnitTestFixture().init();
    28     }
     33    @Rule
     34    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     35    public JOSMTestRules test = new JOSMTestRules().preferences().assertionsInEDT();
    2936
    3037    private static PrefEntry newPrefEntry(String value) {
     
    4350    @Test
    4451    public void testPreferencesTable() {
     52        new JOptionPaneSimpleMocker(ImmutableMap.of(
     53            "Please select the row to edit.", JOptionPane.OK_OPTION,
     54            "Please select the row to delete.", JOptionPane.OK_OPTION
     55        ));
     56        new ExtendedDialogMocker() {
     57            @Override
     58            protected int getMockResult(final ExtendedDialog instance) {
     59                if (instance.getTitle().equals("Add setting")) {
     60                    return 1 + this.getButtonPositionFromLabel(instance, "Cancel");
     61                } else {
     62                    return super.getMockResult(instance);
     63                }
     64            }
     65        };
    4566        PreferencesTable t = newTable();
    4667        t.fireDataChanged();
  • trunk/test/unit/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferenceTest.java

    r11974 r14052  
    1010import java.util.Collections;
    1111
    12 import org.junit.BeforeClass;
     12import org.junit.Rule;
    1313import org.junit.Test;
    14 import org.openstreetmap.josm.JOSMFixture;
    1514import org.openstreetmap.josm.TestUtils;
    1615import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
     
    1918import org.openstreetmap.josm.plugins.PluginException;
    2019import org.openstreetmap.josm.plugins.PluginInformation;
     20import org.openstreetmap.josm.testutils.mockers.HelpAwareOptionPaneMocker;
     21import org.openstreetmap.josm.testutils.JOSMTestRules;
     22
     23import com.google.common.collect.ImmutableMap;
     24
     25import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
    2126
    2227/**
     
    2429 */
    2530public class PluginPreferenceTest {
    26 
    2731    /**
    2832     * Setup test.
    2933     */
    30     @BeforeClass
    31     public static void setUpBeforeClass() {
    32         JOSMFixture.createUnitTestFixture().init();
    33     }
     34    @Rule
     35    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     36    public JOSMTestRules test = new JOSMTestRules().preferences().assertionsInEDT().platform();
    3437
    3538    /**
     
    4851    public static PluginInformation getDummyPluginInformation() throws PluginException {
    4952        return new PluginInformation(
    50                 new File(TestUtils.getTestDataRoot() + "plugin/dummy_plugin.jar"), "dummy_plugin");
     53                new File(TestUtils.getTestDataRoot() + "__files/plugin/dummy_plugin.v31772.jar"), "dummy_plugin");
    5154    }
    5255
     
    8992    @Test
    9093    public void testNotifyDownloadResults() {
     94        new HelpAwareOptionPaneMocker(ImmutableMap.<String, Object>builder()
     95            .put("<html></html>", "OK")  // (buildDownloadSummary() output was empty)
     96            .put("<html>Please restart JOSM to activate the downloaded plugins.</html>", "OK")
     97            .build()
     98        );
     99
    91100        PluginDownloadTask task = new PluginDownloadTask(NullProgressMonitor.INSTANCE, Collections.<PluginInformation>emptyList(), "");
    92101        PluginPreference.notifyDownloadResults(null, task, false);
  • trunk/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java

    r13812 r14052  
    33
    44import java.awt.Color;
     5import java.awt.Window;
     6import java.awt.event.WindowEvent;
    57import java.io.ByteArrayInputStream;
    68import java.io.File;
     
    810import java.security.GeneralSecurityException;
    911import java.text.MessageFormat;
     12import java.util.Arrays;
     13import java.util.Map;
    1014import java.util.TimeZone;
     15import java.util.logging.Handler;
    1116
    1217import org.junit.rules.TemporaryFolder;
     
    3742import org.openstreetmap.josm.io.OsmTransferCanceledException;
    3843import org.openstreetmap.josm.spi.preferences.Config;
     44import org.openstreetmap.josm.spi.preferences.Setting;
     45import org.openstreetmap.josm.testutils.mockers.EDTAssertionMocker;
     46import org.openstreetmap.josm.testutils.mockers.WindowlessMapViewStateMocker;
     47import org.openstreetmap.josm.testutils.mockers.WindowlessNavigatableComponentMocker;
    3948import org.openstreetmap.josm.tools.I18n;
    4049import org.openstreetmap.josm.tools.JosmRuntimeException;
     
    4453import org.openstreetmap.josm.tools.Territories;
    4554import org.openstreetmap.josm.tools.date.DateUtils;
     55
     56import org.awaitility.Awaitility;
    4657
    4758import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     
    6475    private String assumeRevisionString;
    6576    private Version originalVersion;
     77    private Runnable mapViewStateMockingRunnable;
     78    private Runnable navigableComponentMockingRunnable;
     79    private Runnable edtAssertionMockingRunnable;
    6680    private boolean platform;
    6781    private boolean useProjection;
     
    256270        territories();
    257271        rlTraffic = true;
     272        return this;
     273    }
     274
     275    /**
     276     * Re-raise AssertionErrors thrown in the EDT where they would have normally been swallowed.
     277     * @return this instance, for easy chaining
     278     */
     279    public JOSMTestRules assertionsInEDT() {
     280        return this.assertionsInEDT(EDTAssertionMocker::new);
     281    }
     282
     283    /**
     284     * Re-raise AssertionErrors thrown in the EDT where they would have normally been swallowed.
     285     * @param edtAssertionMockingRunnable Runnable for initializing this functionality
     286     *
     287     * @return this instance, for easy chaining
     288     */
     289    public JOSMTestRules assertionsInEDT(final Runnable edtAssertionMockingRunnable) {
     290        this.edtAssertionMockingRunnable = edtAssertionMockingRunnable;
    258291        return this;
    259292    }
     
    297330     */
    298331    public JOSMTestRules main() {
     332        return this.main(
     333            WindowlessMapViewStateMocker::new,
     334            WindowlessNavigatableComponentMocker::new
     335        );
     336    }
     337
     338    /**
     339     * Use the {@link Main#main}, {@code Main.contentPanePrivate}, {@code Main.mainPanel},
     340     *         global variables in this test.
     341     * @param mapViewStateMockingRunnable Runnable to use for mocking out any required parts of
     342     *        {@link org.openstreetmap.josm.gui.MapViewState}, null to skip.
     343     * @param navigableComponentMockingRunnable Runnable to use for mocking out any required parts
     344     *        of {@link org.openstreetmap.josm.gui.NavigatableComponent}, null to skip.
     345     *
     346     * @return this instance, for easy chaining
     347     */
     348    public JOSMTestRules main(
     349        final Runnable mapViewStateMockingRunnable,
     350        final Runnable navigableComponentMockingRunnable
     351    ) {
    299352        platform();
    300         main = true;
     353        this.main = true;
     354        this.mapViewStateMockingRunnable = mapViewStateMockingRunnable;
     355        this.navigableComponentMockingRunnable = navigableComponentMockingRunnable;
    301356        return this;
    302357    }
     
    344399     */
    345400    protected void before() throws InitializationError, ReflectiveOperationException {
    346         // Tests are running headless by default.
    347         System.setProperty("java.awt.headless", "true");
    348 
    349401        cleanUpFromJosmFixture();
    350402
     
    355407        }
    356408
     409        // Add JOSM home
     410        if (josmHome != null) {
     411            try {
     412                File home = josmHome.newFolder();
     413                System.setProperty("josm.home", home.getAbsolutePath());
     414                JosmBaseDirectories.getInstance().clearMemos();
     415            } catch (IOException e) {
     416                throw new InitializationError(e);
     417            }
     418        }
     419
    357420        Config.setPreferencesInstance(Main.pref);
    358421        Config.setBaseDirectoriesProvider(JosmBaseDirectories.getInstance());
    359422        // All tests use the same timezone.
    360423        TimeZone.setDefault(DateUtils.UTC);
     424
     425        // Force log handers to reacquire reference to (junit's fake) stdout/stderr
     426        for (Handler handler : Logging.getLogger().getHandlers()) {
     427            if (handler instanceof Logging.ReacquiringConsoleHandler) {
     428                handler.flush();
     429                ((Logging.ReacquiringConsoleHandler) handler).reacquireOutputStream();
     430            }
     431        }
    361432        // Set log level to info
    362433        Logging.setLogLevel(Logging.LEVEL_INFO);
     434
    363435        // Assume anonymous user
    364436        UserIdentityManager.getInstance().setAnonymous();
     
    373445        }
    374446
    375         // Add JOSM home
    376         if (josmHome != null) {
    377             try {
    378                 File home = josmHome.newFolder();
    379                 System.setProperty("josm.home", home.getAbsolutePath());
    380             } catch (IOException e) {
    381                 throw new InitializationError(e);
    382             }
    383         }
    384 
    385447        // Add preferences
    386448        if (usePreferences) {
     449            @SuppressWarnings("unchecked")
     450            final Map<String, Setting<?>> defaultsMap = (Map<String, Setting<?>>) TestUtils.getPrivateField(Main.pref, "defaultsMap");
     451            defaultsMap.clear();
    387452            Main.pref.resetToInitialState();
    388453            Main.pref.enableSaveOnPut(false);
     
    448513        }
    449514
     515        if (this.edtAssertionMockingRunnable != null) {
     516            this.edtAssertionMockingRunnable.run();
     517        }
     518
    450519        if (commands) {
    451520            // TODO: Implement a more selective version of this once Main is restructured.
     
    453522        } else {
    454523            if (main) {
     524                // apply mockers to MapViewState and NavigableComponent whether we're headless or not
     525                // as we generally don't create the josm main window even in non-headless mode.
     526                if (this.mapViewStateMockingRunnable != null) {
     527                    this.mapViewStateMockingRunnable.run();
     528                }
     529                if (this.navigableComponentMockingRunnable != null) {
     530                    this.navigableComponentMockingRunnable.run();
     531                }
     532
    455533                new MainApplication();
    456534                JOSMFixture.initContentPane();
     
    500578    protected void after() throws ReflectiveOperationException {
    501579        // Sync AWT Thread
    502         GuiHelper.runInEDTAndWait(new Runnable() {
    503             @Override
    504             public void run() {
    505             }
    506         });
     580        GuiHelper.runInEDTAndWait(() -> { });
     581        // Sync worker thread
     582        final boolean[] queueEmpty = {false};
     583        MainApplication.worker.submit(() -> queueEmpty[0] = true);
     584        Awaitility.await().forever().until(() -> queueEmpty[0]);
    507585        // Remove all layers
    508586        cleanLayerEnvironment();
     
    517595            TestUtils.setPrivateStaticField(Version.class, "instance", this.originalVersion);
    518596        }
     597
     598        Window[] windows = Window.getWindows();
     599        if (windows.length != 0) {
     600            Logging.info(
     601                "Attempting to close {0} windows left open by tests: {1}",
     602                windows.length,
     603                Arrays.toString(windows)
     604            );
     605        }
     606        GuiHelper.runInEDTAndWait(() -> {
     607            for (Window window : windows) {
     608                window.dispatchEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSING));
     609                window.dispose();
     610            }
     611        });
    519612
    520613        // Parts of JOSM uses weak references - destroy them.
     
    570663                    throw exception;
    571664                } else {
     665                    Logging.debug("Thread state at timeout: {0}", Thread.getAllStackTraces());
    572666                    throw new Exception(MessageFormat.format("Test timed out after {0}ms", timeout));
    573667                }
Note: See TracChangeset for help on using the changeset viewer.