source: josm/trunk/test/unit/org/openstreetmap/josm/gui/NavigatableComponentTest.java

Last change on this file was 18870, checked in by taylor.smock, 6 months ago

See #16567: Update to JUnit 5

This converts most tests to use @Annotations. There are also some performance
improvements as it relates to tests.

  • Property svn:eol-style set to native
File size: 11.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.hamcrest.MatcherAssert.assertThat;
5import static org.junit.jupiter.api.Assertions.assertEquals;
6import static org.junit.jupiter.api.Assertions.assertNotNull;
7import static org.junit.jupiter.api.Assertions.assertNull;
8import static org.junit.jupiter.api.Assertions.assertSame;
9
10import java.awt.Point;
11import java.awt.Rectangle;
12import java.awt.event.MouseEvent;
13import java.awt.geom.Point2D;
14import java.util.Objects;
15import java.util.concurrent.atomic.AtomicReference;
16
17import javax.swing.JPanel;
18
19import org.CustomMatchers;
20import org.hamcrest.CustomTypeSafeMatcher;
21import org.hamcrest.Matcher;
22import org.junit.jupiter.api.BeforeEach;
23import org.junit.jupiter.api.Test;
24import org.openstreetmap.josm.data.Bounds;
25import org.openstreetmap.josm.data.ProjectionBounds;
26import org.openstreetmap.josm.data.coor.EastNorth;
27import org.openstreetmap.josm.data.coor.LatLon;
28import org.openstreetmap.josm.data.osm.DataSet;
29import org.openstreetmap.josm.data.osm.Node;
30import org.openstreetmap.josm.data.projection.ProjectionRegistry;
31import org.openstreetmap.josm.gui.layer.OsmDataLayer;
32import org.openstreetmap.josm.gui.util.GuiHelper;
33import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
34import org.openstreetmap.josm.testutils.annotations.Projection;
35
36/**
37 * Some tests for the {@link NavigatableComponent} class.
38 * @author Michael Zangl
39 *
40 */
41@BasicPreferences
42@Projection // We need the projection for coordinate conversions.
43class NavigatableComponentTest {
44
45 private static final class NavigatableComponentMock extends NavigatableComponent {
46 @Override
47 public Point getLocationOnScreen() {
48 return new Point(30, 40);
49 }
50
51 @Override
52 protected boolean isVisibleOnScreen() {
53 return true;
54 }
55
56 @Override
57 public void processMouseMotionEvent(MouseEvent mouseEvent) {
58 super.processMouseMotionEvent(mouseEvent);
59 }
60 }
61
62 private static final int HEIGHT = 200;
63 private static final int WIDTH = 300;
64 private NavigatableComponentMock component;
65
66 /**
67 * Create a new, fresh {@link NavigatableComponent}
68 */
69 @BeforeEach
70 public void setUp() {
71 component = new NavigatableComponentMock();
72 component.setBounds(new Rectangle(WIDTH, HEIGHT));
73 // wait for the event to be propagated.
74 GuiHelper.runInEDTAndWait(() -> { /* Do nothing */ });
75 component.setVisible(true);
76 JPanel parent = new JPanel();
77 parent.add(component);
78 component.updateLocationState();
79 }
80
81 /**
82 * Test if the default scale was set correctly.
83 */
84 @Test
85 void testDefaultScale() {
86 assertEquals(ProjectionRegistry.getProjection().getDefaultZoomInPPD(), component.getScale(), 0.00001);
87 }
88
89 /**
90 * Tests {@link NavigatableComponent#getPoint2D(EastNorth)}
91 */
92 @Test
93 void testPoint2DEastNorth() {
94 assertThat(component.getPoint2D((EastNorth) null), CustomMatchers.is(new Point2D.Double()));
95 Point2D shouldBeCenter = component.getPoint2D(component.getCenter());
96 assertThat(shouldBeCenter, CustomMatchers.is(new Point2D.Double(WIDTH / 2.0, HEIGHT / 2.0)));
97
98 EastNorth testPoint = component.getCenter().add(300 * component.getScale(), 200 * component.getScale());
99 Point2D testPointConverted = component.getPoint2D(testPoint);
100 assertThat(testPointConverted, CustomMatchers.is(new Point2D.Double(WIDTH / 2.0 + 300, HEIGHT / 2.0 - 200)));
101 }
102
103 /**
104 * TODO: Implement this test.
105 */
106 @Test
107 void testPoint2DLatLon() {
108 assertThat(component.getPoint2D((LatLon) null), CustomMatchers.is(new Point2D.Double()));
109 // TODO: Really test this.
110 }
111
112 /**
113 * Tests {@link NavigatableComponent#zoomTo(LatLon)}
114 */
115 @Test
116 void testZoomToLatLon() {
117 component.zoomTo(new LatLon(10, 10));
118 Point2D shouldBeCenter = component.getPoint2D(new LatLon(10, 10));
119 // 0.5 pixel tolerance, see isAfterZoom
120 assertEquals(shouldBeCenter.getX(), WIDTH / 2., 0.5);
121 assertEquals(shouldBeCenter.getY(), HEIGHT / 2., 0.5);
122 }
123
124 /**
125 * Tests {@link NavigatableComponent#zoomToFactor(double)} and {@link NavigatableComponent#zoomToFactor(EastNorth, double)}
126 */
127 @Test
128 void testZoomToFactor() {
129 EastNorth center = component.getCenter();
130 double initialScale = component.getScale();
131
132 // zoomToFactor(double)
133 component.zoomToFactor(0.5);
134 assertEquals(initialScale / 2, component.getScale(), 0.00000001);
135 assertThat(component.getCenter(), isAfterZoom(center, component.getScale()));
136 component.zoomToFactor(2);
137 assertEquals(initialScale, component.getScale(), 0.00000001);
138 assertThat(component.getCenter(), isAfterZoom(center, component.getScale()));
139
140 // zoomToFactor(EastNorth, double)
141 EastNorth newCenter = new EastNorth(10, 20);
142 component.zoomToFactor(newCenter, 0.5);
143 assertEquals(initialScale / 2, component.getScale(), 0.00000001);
144 assertThat(component.getCenter(), isAfterZoom(newCenter, component.getScale()));
145 component.zoomToFactor(newCenter, 2);
146 assertEquals(initialScale, component.getScale(), 0.00000001);
147 assertThat(component.getCenter(), isAfterZoom(newCenter, component.getScale()));
148 }
149
150 /**
151 * Tests {@link NavigatableComponent#getEastNorth(int, int)}
152 */
153 @Test
154 void testGetEastNorth() {
155 EastNorth center = component.getCenter();
156 assertThat(component.getEastNorth(WIDTH / 2, HEIGHT / 2), CustomMatchers.is(center));
157
158 EastNorth testPoint = component.getCenter().add(WIDTH * component.getScale(), HEIGHT * component.getScale());
159 assertThat(component.getEastNorth(3 * WIDTH / 2, -HEIGHT / 2), CustomMatchers.is(testPoint));
160 }
161
162 /**
163 * Tests {@link NavigatableComponent#zoomToFactor(double, double, double)}
164 */
165 @Test
166 void testZoomToFactorCenter() {
167 // zoomToFactor(double, double, double)
168 // assumes getEastNorth works as expected
169 EastNorth testPoint1 = component.getEastNorth(0, 0);
170 EastNorth testPoint2 = component.getEastNorth(200, 150);
171 double initialScale = component.getScale();
172
173 component.zoomToFactor(0, 0, 0.5);
174 assertEquals(initialScale / 2, component.getScale(), 0.00000001);
175 assertThat(component.getEastNorth(0, 0), isAfterZoom(testPoint1, component.getScale()));
176 component.zoomToFactor(0, 0, 2);
177 assertEquals(initialScale, component.getScale(), 0.00000001);
178 assertThat(component.getEastNorth(0, 0), isAfterZoom(testPoint1, component.getScale()));
179
180 component.zoomToFactor(200, 150, 0.5);
181 assertEquals(initialScale / 2, component.getScale(), 0.00000001);
182 assertThat(component.getEastNorth(200, 150), isAfterZoom(testPoint2, component.getScale()));
183 component.zoomToFactor(200, 150, 2);
184 assertEquals(initialScale, component.getScale(), 0.00000001);
185 assertThat(component.getEastNorth(200, 150), isAfterZoom(testPoint2, component.getScale()));
186
187 }
188
189 /**
190 * Tests {@link NavigatableComponent#getProjectionBounds()}
191 */
192 @Test
193 void testGetProjectionBounds() {
194 ProjectionBounds bounds = component.getProjectionBounds();
195 assertThat(bounds.getCenter(), CustomMatchers.is(component.getCenter()));
196
197 assertThat(bounds.getMin(), CustomMatchers.is(component.getEastNorth(0, HEIGHT)));
198 assertThat(bounds.getMax(), CustomMatchers.is(component.getEastNorth(WIDTH, 0)));
199 }
200
201 /**
202 * Tests {@link NavigatableComponent#getRealBounds()}
203 */
204 @Test
205 void testGetRealBounds() {
206 Bounds bounds = component.getRealBounds();
207 assertThat(bounds.getCenter(), CustomMatchers.is(component.getLatLon(WIDTH / 2, HEIGHT / 2)));
208
209 assertThat(bounds.getMin(), CustomMatchers.is(component.getLatLon(0, HEIGHT)));
210 assertThat(bounds.getMax(), CustomMatchers.is(component.getLatLon(WIDTH, 0)));
211 }
212
213 @Test
214 void testHoverListeners() {
215 AtomicReference<PrimitiveHoverListener.PrimitiveHoverEvent> hoverEvent = new AtomicReference<>();
216 PrimitiveHoverListener testListener = hoverEvent::set;
217 assertNull(hoverEvent.get());
218 component.addNotify();
219 component.addPrimitiveHoverListener(testListener);
220 DataSet ds = new DataSet();
221 MainApplication.getLayerManager().addLayer(new OsmDataLayer(ds, "testHoverListeners", null));
222 LatLon center = component.getRealBounds().getCenter();
223 Node node1 = new Node(center);
224 ds.addPrimitive(node1);
225 double x = component.getBounds().getCenterX();
226 double y = component.getBounds().getCenterY();
227 // Check hover over primitive
228 MouseEvent node1Event = new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(),
229 0, (int) x, (int) y, 0, false, MouseEvent.NOBUTTON);
230 component.processMouseMotionEvent(node1Event);
231 GuiHelper.runInEDTAndWait(() -> { /* Sync */ });
232 PrimitiveHoverListener.PrimitiveHoverEvent event = hoverEvent.getAndSet(null);
233 assertNotNull(event);
234 assertSame(node1, event.getHoveredPrimitive());
235 assertNull(event.getPreviousPrimitive());
236 assertSame(node1Event, event.getMouseEvent());
237 // Check moving to the (same) primitive. No new mouse motion event should be called.
238 component.processMouseMotionEvent(node1Event);
239 GuiHelper.runInEDTAndWait(() -> { /* Sync */ });
240 event = hoverEvent.getAndSet(null);
241 assertNull(event);
242 // Check moving off primitive. A new mouse motion event should be called with the previous primitive and null.
243 MouseEvent noNodeEvent =
244 new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false, MouseEvent.NOBUTTON);
245 component.processMouseMotionEvent(noNodeEvent);
246 GuiHelper.runInEDTAndWait(() -> { /* Sync */ });
247 event = hoverEvent.getAndSet(null);
248 assertNotNull(event);
249 assertSame(node1, event.getPreviousPrimitive());
250 assertNull(event.getHoveredPrimitive());
251 assertSame(noNodeEvent, event.getMouseEvent());
252 // Check moving to area with no primitive with no previous hover primitive
253 component.processMouseMotionEvent(
254 new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 1, 1, 0, false, MouseEvent.NOBUTTON));
255 assertNull(hoverEvent.get());
256 }
257
258 /**
259 * Check that EastNorth is the same as expected after zooming the NavigatableComponent.
260 * <p>
261 * Adds tolerance of 0.5 pixel for pixel grid alignment, see
262 * {@link NavigatableComponent#zoomTo(EastNorth, double, boolean)}
263 * @param expected expected
264 * @param scale current scale
265 * @return Matcher object
266 */
267 private Matcher<EastNorth> isAfterZoom(EastNorth expected, double scale) {
268 return new CustomTypeSafeMatcher<EastNorth>(Objects.toString(expected)) {
269 @Override
270 protected boolean matchesSafely(EastNorth actual) {
271 // compare pixels (east/north divided by scale)
272 return Math.abs((expected.getX() - actual.getX()) / scale) <= 0.5
273 && Math.abs((expected.getY() - actual.getY()) / scale) <= 0.5;
274 }
275 };
276 }
277
278}
Note: See TracBrowser for help on using the repository browser.