Changeset 18454 in josm for trunk/test/unit


Ignore:
Timestamp:
2022-05-19T20:09:13+02:00 (2 years ago)
Author:
taylor.smock
Message:

Fix #21558: IOOBE in NotesDialog$NoteTableModel.getElementAt

This is caused when a user has a filter in the note panel,
and performs an action that removes the last note from
the panel.

Example:

  1. User filters on "open"
  2. User closes all notes
Location:
trunk/test/unit/org/openstreetmap/josm
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/test/unit/org/openstreetmap/josm/gui/dialogs/NotesDialogTest.java

    r18037 r18454  
    22package org.openstreetmap.josm.gui.dialogs;
    33
     4import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
    45import static org.junit.jupiter.api.Assertions.assertEquals;
    56import static org.junit.jupiter.api.Assertions.assertFalse;
    67import static org.junit.jupiter.api.Assertions.assertTrue;
     8import static org.openstreetmap.josm.tools.I18n.tr;
    79
    810import java.time.Instant;
     11import java.util.Collections;
    912
    1013import javax.swing.JLabel;
    1114import javax.swing.JList;
    1215
     16import org.junit.jupiter.api.Test;
     17import org.junit.jupiter.api.extension.RegisterExtension;
     18import org.junit.platform.commons.util.ReflectionUtils;
     19import org.openstreetmap.josm.TestUtils;
    1320import org.openstreetmap.josm.data.coor.LatLon;
    1421import org.openstreetmap.josm.data.notes.Note;
    1522import org.openstreetmap.josm.data.notes.NoteComment;
    1623import org.openstreetmap.josm.data.osm.User;
     24import org.openstreetmap.josm.gui.ExtendedDialog;
     25import org.openstreetmap.josm.gui.MainApplication;
    1726import org.openstreetmap.josm.gui.dialogs.NotesDialog.NoteRenderer;
     27import org.openstreetmap.josm.gui.layer.NoteLayer;
     28import org.openstreetmap.josm.gui.widgets.JosmTextField;
     29import org.openstreetmap.josm.testutils.JOSMTestRules;
    1830import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
    19 
    20 import org.junit.jupiter.api.Test;
     31import org.openstreetmap.josm.testutils.mockers.ExtendedDialogMocker;
    2132
    2233/**
     
    2536@BasicPreferences
    2637class NotesDialogTest {
     38    /** Only needed for {@link #testTicket21558} */
     39    @RegisterExtension
     40    JOSMTestRules rules = new JOSMTestRules().main().projection();
    2741    private Note createMultiLineNote() {
    2842        Note note = new Note(LatLon.ZERO);
     
    5670        assertFalse(NotesDialog.matchesNote("reopened", note));
    5771    }
     72
     73    /**
     74     * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/21558>#21558</a>
     75     */
     76    @Test
     77    void testTicket21558() throws Exception {
     78        TestUtils.assumeWorkingJMockit();
     79        new ExtendedDialogMocker(Collections.singletonMap(tr("Close note"), tr("Close note"))) {
     80            @Override
     81            protected String getString(ExtendedDialog instance) {
     82                return instance.getTitle();
     83            }
     84        };
     85        final NotesDialog notesDialog = new NotesDialog();
     86        final NotesDialog.CloseAction closeAction = (NotesDialog.CloseAction) ReflectionUtils
     87                .tryToReadFieldValue(NotesDialog.class, "closeAction", notesDialog).get();
     88        final JosmTextField filter = (JosmTextField) ReflectionUtils
     89                .tryToReadFieldValue(NotesDialog.class, "filter", notesDialog).get();
     90        final NoteLayer noteLayer = new NoteLayer();
     91        MainApplication.getLayerManager().addLayer(noteLayer);
     92        final Note note = createMultiLineNote();
     93        note.setState(Note.State.OPEN);
     94        noteLayer.getNoteData().addNotes(Collections.singleton(note));
     95        noteLayer.getNoteData().setSelectedNote(note);
     96        filter.setText("open");
     97        assertDoesNotThrow(() -> closeAction.actionPerformed(null));
     98    }
    5899}
  • trunk/test/unit/org/openstreetmap/josm/testutils/mockers/ExtendedDialogMocker.java

    r17275 r18454  
    143143    }
    144144
     145    /**
     146     * Get the result field for an extended dialog instance
     147     * @param instance The instance to get the result field for
     148     * @return The result field. May be private.
     149     * @throws NoSuchFieldException If the field cannot be found. Should never be thrown.
     150     */
     151    protected Field getResultField(ExtendedDialog instance) throws NoSuchFieldException {
     152        // Note that subclasses of ExtendedDialogMocker will not have "result" as a declared field.
     153        // Iterate up the chain until we get to a field that has "result" as a declared field.
     154        // Only reason for this is just in case someone overrides the logic in ExtendedDialog.
     155        Class<?> clazz = instance.getClass();
     156        Field resultField = null;
     157        // Store the exception, if any
     158        NoSuchFieldException noSuchFieldException = null;
     159        while (!Object.class.equals(clazz) && resultField == null) {
     160            try {
     161                resultField = clazz.getDeclaredField("result");
     162            } catch (NoSuchFieldException e) {
     163                clazz = instance.getClass().getSuperclass();
     164                // Only save the first exception
     165                if (noSuchFieldException == null) {
     166                    noSuchFieldException = e;
     167                }
     168            }
     169        }
     170        if (resultField == null) {
     171            throw noSuchFieldException;
     172        }
     173        return resultField;
     174    }
     175
    145176    @Mock
    146177    private void setupDialog(final Invocation invocation) {
     
    160191                final int mockResult = this.getMockResult(instance);
    161192                // TODO check validity of mockResult?
    162                 Field resultField = instance.getClass().getDeclaredField("result");
     193                final Field resultField = this.getResultField(instance);
    163194                resultField.setAccessible(true);
    164195                resultField.set(instance, mockResult);
Note: See TracChangeset for help on using the changeset viewer.