source: josm/trunk/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java@ 18893

Last change on this file since 18893 was 18893, checked in by taylor.smock, 8 months ago

Fix #16567: Upgrade to JUnit 5

JOSMTestRules and JOSMTestFixture can reset the default JOSM profile, which can
be unexpected for new contributors. This updates all tests to use JUnit 5 and
the new JUnit 5 annotations.

This also renames MapCSSStyleSourceFilterTest to MapCSSStyleSourceFilterPerformanceTest
to match the naming convention for performance tests and fixes some lint issues.

This was tested by running all tests individually and together.

  • Property svn:eol-style set to native
File size: 35.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static java.util.concurrent.TimeUnit.MILLISECONDS;
5import static org.junit.jupiter.api.Assertions.assertArrayEquals;
6import static org.junit.jupiter.api.Assertions.assertEquals;
7import static org.junit.jupiter.api.Assertions.assertFalse;
8import static org.junit.jupiter.api.Assertions.assertInstanceOf;
9import static org.junit.jupiter.api.Assertions.assertTrue;
10import static org.junit.jupiter.api.Assertions.fail;
11import static org.openstreetmap.josm.tools.I18n.tr;
12
13import java.awt.Color;
14import java.awt.Component;
15import java.awt.Graphics2D;
16import java.awt.event.ComponentEvent;
17import java.awt.image.BufferedImage;
18import java.util.ArrayList;
19import java.util.Arrays;
20import java.util.HashMap;
21import java.util.Map;
22import java.util.Objects;
23import java.util.concurrent.Callable;
24import java.util.regex.Matcher;
25
26import javax.swing.JCheckBoxMenuItem;
27import javax.swing.JMenuItem;
28import javax.swing.JPopupMenu;
29
30import org.awaitility.Awaitility;
31import org.junit.jupiter.api.Test;
32import org.openstreetmap.josm.TestUtils;
33import org.openstreetmap.josm.data.Bounds;
34import org.openstreetmap.josm.data.DataSource;
35import org.openstreetmap.josm.data.imagery.ImageryInfo;
36import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
37import org.openstreetmap.josm.data.osm.DataSet;
38import org.openstreetmap.josm.data.projection.ProjectionRegistry;
39import org.openstreetmap.josm.data.projection.Projections;
40import org.openstreetmap.josm.gui.MainApplication;
41import org.openstreetmap.josm.gui.MapView;
42import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
43import org.openstreetmap.josm.gui.bbox.SourceButton;
44import org.openstreetmap.josm.gui.layer.ImageryLayer;
45import org.openstreetmap.josm.gui.layer.LayerManagerTest.TestLayer;
46import org.openstreetmap.josm.gui.layer.OsmDataLayer;
47import org.openstreetmap.josm.gui.util.GuiHelper;
48import org.openstreetmap.josm.spi.preferences.Config;
49import org.openstreetmap.josm.testutils.ImagePatternMatching;
50import org.openstreetmap.josm.testutils.annotations.FakeImagery;
51import org.openstreetmap.josm.testutils.annotations.Main;
52import org.openstreetmap.josm.testutils.annotations.MeasurementSystem;
53import org.openstreetmap.josm.testutils.annotations.Projection;
54
55/**
56 * Unit tests of {@link MinimapDialog} class.
57 */
58@FakeImagery
59@Main
60@Projection
61// Needed since testShowDownloadedAreaLayerSwitching expects the measurement to be imperial
62@MeasurementSystem("Imperial")
63class MinimapDialogTest {
64 /**
65 * Unit test of {@link MinimapDialog} class.
66 */
67 @Test
68 void testMinimapDialog() {
69 MinimapDialog dlg = new MinimapDialog();
70 dlg.showDialog();
71 assertTrue(dlg.isVisible());
72 dlg.hideDialog();
73 assertFalse(dlg.isVisible());
74 }
75
76 @FunctionalInterface
77 protected interface ThrowingRunnable {
78 void run() throws Throwable;
79 }
80
81 protected static Runnable uncheckExceptions(final ThrowingRunnable tr) {
82 return (() -> {
83 try {
84 tr.run();
85 } catch (Throwable e) {
86 throw new RuntimeException(e);
87 }
88 });
89 }
90
91 protected void assertSingleSelectedSourceLabel(final String label) {
92 JPopupMenu menu = this.sourceButton.getPopupMenu();
93 boolean found = false;
94 for (Component c: menu.getComponents()) {
95 if (c instanceof JPopupMenu.Separator) {
96 break;
97 } else {
98 boolean equalText = ((JMenuItem) c).getText().equals(label);
99 boolean isSelected = ((JMenuItem) c).isSelected();
100 assertEquals(equalText, isSelected);
101 if (equalText) {
102 assertFalse(found, "Second selected source found");
103 found = true;
104 }
105 }
106 }
107 assertTrue(found, "Selected source not found in menu");
108 }
109
110 protected void clickSourceMenuItemByLabel(final String label) {
111 try {
112 GuiHelper.runInEDTAndWaitWithException(() -> {
113 JPopupMenu menu = this.sourceButton.getPopupMenu();
114 for (Component c: menu.getComponents()) {
115 if (c instanceof JPopupMenu.Separator) {
116 // sources should all come before any separators
117 break;
118 } else if (Objects.equals(((JMenuItem) c).getText(), label)) {
119 ((JMenuItem) c).doClick();
120 return;
121 }
122 // else continue...
123 }
124 fail("Expected JMenuItem with text " + label + " not found");
125 });
126 } catch (Throwable e) {
127 throw new RuntimeException(String.format("Failed to find menu item with label %s: %s", label, e), e);
128 }
129 }
130
131 protected void assertSourceLabelsVisible(final String... labels) {
132 GuiHelper.runInEDTAndWaitWithException(() -> {
133 final ArrayList<String> menuLabels = new ArrayList<>();
134 final JPopupMenu menu = this.sourceButton.getPopupMenu();
135 for (Component c: menu.getComponents()) {
136 if (c instanceof JPopupMenu.Separator) {
137 break;
138 }
139 menuLabels.add(((JMenuItem) c).getText());
140 }
141
142 assertArrayEquals(
143 labels,
144 menuLabels.toArray()
145 );
146 });
147 }
148
149 private MinimapDialog minimap;
150 private SlippyMapBBoxChooser slippyMap;
151 private SourceButton sourceButton;
152 private Callable<Boolean> slippyMapTasksFinished;
153
154 private static BufferedImage paintedSlippyMap;
155
156 protected void setUpMiniMap() {
157 GuiHelper.runInEDTAndWaitWithException(uncheckExceptions(() -> {
158 this.minimap = new MinimapDialog();
159 this.minimap.setSize(300, 200);
160 this.minimap.showDialog();
161 this.slippyMap = (SlippyMapBBoxChooser) TestUtils.getPrivateField(this.minimap, "slippyMap");
162 this.sourceButton = (SourceButton) TestUtils.getPrivateField(this.slippyMap, "iSourceButton");
163
164 // get minimap in a paintable state
165 this.minimap.addNotify();
166 this.minimap.doLayout();
167 }));
168
169 this.slippyMapTasksFinished = () -> !this.slippyMap.getTileController().getTileLoader().hasOutstandingTasks();
170 }
171
172 protected void paintSlippyMap() {
173 if (paintedSlippyMap == null ||
174 paintedSlippyMap.getWidth() != this.slippyMap.getSize().width ||
175 paintedSlippyMap.getHeight() != this.slippyMap.getSize().height) {
176 paintedSlippyMap = new BufferedImage(
177 this.slippyMap.getSize().width,
178 this.slippyMap.getSize().height,
179 BufferedImage.TYPE_INT_RGB
180 );
181 } // else reuse existing one - allocation is expensive
182
183 // clear background to a recognizably "wrong" color & dispose our Graphics2D so we don't risk carrying over
184 // any state
185 Graphics2D g = paintedSlippyMap.createGraphics();
186 g.setBackground(Color.BLUE);
187 g.clearRect(0, 0, paintedSlippyMap.getWidth(), paintedSlippyMap.getHeight());
188 g.dispose();
189
190 g = paintedSlippyMap.createGraphics();
191 this.slippyMap.paintAll(g);
192 }
193
194 /**
195 * Tests to switch imagery source.
196 */
197 @Test
198 void testSourceSwitching() {
199 // relevant prefs starting out empty, should choose the first source and have shown download area enabled
200 // (not that there's a data layer for it to use)
201
202 this.setUpMiniMap();
203
204 // an initial paint operation is required to trigger the tile fetches
205 this.paintSlippyMap();
206
207 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
208
209 this.paintSlippyMap();
210
211 assertEquals(0xffffffff, paintedSlippyMap.getRGB(0, 0));
212
213 this.assertSingleSelectedSourceLabel("White Tiles");
214
215 this.clickSourceMenuItemByLabel("Magenta Tiles");
216 this.assertSingleSelectedSourceLabel("Magenta Tiles");
217 // call paint to trigger new tile fetch
218 this.paintSlippyMap();
219
220 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
221
222 this.paintSlippyMap();
223
224 assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
225
226 this.clickSourceMenuItemByLabel("Green Tiles");
227 this.assertSingleSelectedSourceLabel("Green Tiles");
228 // call paint to trigger new tile fetch
229 this.paintSlippyMap();
230
231 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
232
233 this.paintSlippyMap();
234
235 assertEquals(0xff00ff00, paintedSlippyMap.getRGB(0, 0));
236
237 assertEquals("Green Tiles", Config.getPref().get("slippy_map_chooser.mapstyle", "Fail"));
238 }
239
240 /**
241 * Tests that the apparently-selected TileSource survives the tile sources being refreshed.
242 */
243 @Test
244 void testRefreshSourcesRetainsSelection() {
245 // relevant prefs starting out empty, should choose the first source and have shown download area enabled
246 // (not that there's a data layer for it to use)
247
248 this.setUpMiniMap();
249
250 this.clickSourceMenuItemByLabel("Magenta Tiles");
251 this.assertSingleSelectedSourceLabel("Magenta Tiles");
252
253 // call paint to trigger new tile fetch
254 this.paintSlippyMap();
255
256 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
257
258 this.paintSlippyMap();
259
260 assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
261
262 this.slippyMap.refreshTileSources();
263
264 this.assertSingleSelectedSourceLabel("Magenta Tiles");
265
266 // call paint to trigger new tile fetch
267 this.paintSlippyMap();
268
269 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
270
271 this.paintSlippyMap();
272
273 assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
274 }
275
276 /**
277 * Tests that the currently selected source being removed from ImageryLayerInfo will remain present and
278 * selected in the source menu even after the tile sources have been refreshed.
279 */
280 @Test
281 void testRemovedSourceStillSelected() {
282 // relevant prefs starting out empty, should choose the first source and have shown download area enabled
283 // (not that there's a data layer for it to use)
284
285 this.setUpMiniMap();
286
287 this.clickSourceMenuItemByLabel("Green Tiles");
288
289 ImageryLayerInfo.instance.remove(
290 ImageryLayerInfo.instance.getLayers().stream().filter(i -> i.getName().equals("Green Tiles")).findAny().get()
291 );
292
293 this.assertSingleSelectedSourceLabel("Green Tiles");
294
295 this.slippyMap.refreshTileSources();
296
297 this.assertSingleSelectedSourceLabel("Green Tiles");
298
299 // call paint to trigger new tile fetch
300 this.paintSlippyMap();
301
302 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
303
304 this.paintSlippyMap();
305
306 assertEquals(0xff00ff00, paintedSlippyMap.getRGB(0, 0));
307 }
308
309 /**
310 * Tests the tile source list includes sources only present in the LayerManager
311 */
312 @Test
313 void testTileSourcesFromCurrentLayers() {
314 // relevant prefs starting out empty, should choose the first (ImageryLayerInfo) source and have shown download area enabled
315 // (not that there's a data layer for it to use)
316
317 final ImageryInfo magentaTilesInfo = ImageryLayerInfo.instance.getLayers().stream().filter(
318 i -> i.getName().equals("Magenta Tiles")
319 ).findAny().get();
320 final ImageryInfo blackTilesInfo = ImageryLayerInfo.instance.getLayers().stream().filter(
321 i -> i.getName().equals("Black Tiles")
322 ).findAny().get();
323
324 // first we will remove "Magenta Tiles" from ImageryLayerInfo
325 ImageryLayerInfo.instance.remove(magentaTilesInfo);
326
327 this.setUpMiniMap();
328
329 assertSourceLabelsVisible(
330 "White Tiles",
331 "Black Tiles",
332 "Green Tiles"
333 );
334
335 final ImageryLayer magentaTilesLayer = ImageryLayer.create(magentaTilesInfo);
336 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().addLayer(magentaTilesLayer));
337
338 assertSourceLabelsVisible(
339 "White Tiles",
340 "Black Tiles",
341 "Green Tiles",
342 "Magenta Tiles"
343 );
344
345 this.clickSourceMenuItemByLabel("Magenta Tiles");
346 this.assertSingleSelectedSourceLabel("Magenta Tiles");
347
348 // call paint to trigger new tile fetch
349 this.paintSlippyMap();
350
351 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
352
353 this.paintSlippyMap();
354
355 assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
356
357 final ImageryLayer blackTilesLayer = ImageryLayer.create(blackTilesInfo);
358 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().addLayer(blackTilesLayer));
359
360 assertSourceLabelsVisible(
361 "White Tiles",
362 "Black Tiles",
363 "Green Tiles",
364 "Magenta Tiles"
365 );
366
367 this.clickSourceMenuItemByLabel("Black Tiles");
368 this.assertSingleSelectedSourceLabel("Black Tiles");
369
370 // call paint to trigger new tile fetch
371 this.paintSlippyMap();
372
373 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
374
375 this.paintSlippyMap();
376
377 assertEquals(0xff000000, paintedSlippyMap.getRGB(0, 0));
378
379 // removing magentaTilesLayer while it is *not* the selected TileSource should make it disappear
380 // immediately
381 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().removeLayer(magentaTilesLayer));
382
383 assertSourceLabelsVisible(
384 "White Tiles",
385 "Black Tiles",
386 "Green Tiles"
387 );
388 this.assertSingleSelectedSourceLabel("Black Tiles");
389
390 final ImageryLayer magentaTilesLayer2 = ImageryLayer.create(magentaTilesInfo);
391 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().addLayer(magentaTilesLayer2));
392
393 assertSourceLabelsVisible(
394 "White Tiles",
395 "Black Tiles",
396 "Green Tiles",
397 "Magenta Tiles"
398 );
399
400 this.clickSourceMenuItemByLabel("Magenta Tiles");
401 this.assertSingleSelectedSourceLabel("Magenta Tiles");
402
403 // call paint to trigger new tile fetch
404 this.paintSlippyMap();
405
406 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
407
408 this.paintSlippyMap();
409
410 assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
411
412 // removing magentaTilesLayer while it *is* the selected TileSource...
413 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().removeLayer(magentaTilesLayer2));
414
415 assertSourceLabelsVisible(
416 "White Tiles",
417 "Black Tiles",
418 "Green Tiles",
419 "Magenta Tiles"
420 );
421 this.assertSingleSelectedSourceLabel("Magenta Tiles");
422
423 this.clickSourceMenuItemByLabel("Green Tiles");
424 this.assertSingleSelectedSourceLabel("Green Tiles");
425 assertSourceLabelsVisible(
426 "White Tiles",
427 "Black Tiles",
428 "Green Tiles"
429 );
430
431 // removing blackTilesLayer shouldn't remove it from the menu as it is already in ImageryLayerInfo
432 GuiHelper.runInEDT(() -> MainApplication.getLayerManager().removeLayer(blackTilesLayer));
433
434 this.assertSingleSelectedSourceLabel("Green Tiles");
435 assertSourceLabelsVisible(
436 "White Tiles",
437 "Black Tiles",
438 "Green Tiles"
439 );
440 }
441
442 /**
443 * Tests minimap obeys a saved "mapstyle" preference on startup.
444 */
445 @Test
446 void testSourcePrefObeyed() {
447 Config.getPref().put("slippy_map_chooser.mapstyle", "Green Tiles");
448
449 this.setUpMiniMap();
450
451 this.assertSingleSelectedSourceLabel("Green Tiles");
452
453 // an initial paint operation is required to trigger the tile fetches
454 this.paintSlippyMap();
455
456 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
457
458 this.paintSlippyMap();
459
460 assertEquals(0xff00ff00, paintedSlippyMap.getRGB(0, 0));
461
462 this.clickSourceMenuItemByLabel("Magenta Tiles");
463 this.assertSingleSelectedSourceLabel("Magenta Tiles");
464
465 assertEquals("Magenta Tiles", Config.getPref().get("slippy_map_chooser.mapstyle", "Fail"));
466 }
467
468 /**
469 * Tests minimap handles an unrecognized "mapstyle" preference on startup
470 */
471 @Test
472 void testSourcePrefInvalid() {
473 Config.getPref().put("slippy_map_chooser.mapstyle", "Hooloovoo Tiles");
474
475 this.setUpMiniMap();
476
477 this.assertSingleSelectedSourceLabel("White Tiles");
478
479 // an initial paint operation is required to trigger the tile fetches
480 this.paintSlippyMap();
481
482 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
483
484 this.paintSlippyMap();
485
486 assertEquals(0xffffffff, paintedSlippyMap.getRGB(0, 0));
487 }
488
489 /**
490 * test viewport marker rectangle matches the mapView's aspect ratio
491 */
492 @Test
493 void testViewportAspectRatio() {
494 // Add a test layer to the layer manager to get the MapFrame & MapView
495 MainApplication.getLayerManager().addLayer(new TestLayer());
496
497 Config.getPref().put("slippy_map_chooser.mapstyle", "White Tiles");
498 // ensure projection matches JMapViewer's
499 ProjectionRegistry.setProjection(Projections.getProjectionByCode("EPSG:3857"));
500
501 MapView mapView = MainApplication.getMap().mapView;
502 GuiHelper.runInEDTAndWaitWithException(() -> {
503 mapView.setVisible(true);
504 mapView.addNotify();
505 mapView.doLayout();
506 // ensure we have a square mapView viewport
507 mapView.setBounds(0, 0, 350, 350);
508 });
509
510 this.setUpMiniMap();
511
512 // attempt to set viewport to cover a non-square area
513 mapView.zoomTo(new Bounds(26.27, -18.23, 26.275, -18.229));
514
515 // an initial paint operation is required to trigger the tile fetches
516 this.paintSlippyMap();
517
518 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
519
520 this.paintSlippyMap();
521
522 Map<Integer, String> paletteMap = new HashMap<Integer, String>() {{
523 put(0xffffffff, "w"); // white
524 put(0xff000000, "b"); // black
525 put(0xfff0d1d1, "p"); // pink
526 }};
527
528 Matcher rowMatcher = ImagePatternMatching.rowMatch(
529 paintedSlippyMap,
530 paintedSlippyMap.getHeight()/2,
531 paletteMap,
532 "^(w+)b(p+)b(w+)$",
533 true
534 );
535
536 // (within a tolerance for numerical error) the number of pixels on the left of the viewport marker
537 // should equal the number on the right
538 assertTrue(
539 Math.abs(rowMatcher.group(1).length() - rowMatcher.group(3).length()) < 4,
540 "Viewport marker not horizontally centered"
541 );
542
543 Matcher colMatcher = ImagePatternMatching.columnMatch(
544 paintedSlippyMap,
545 paintedSlippyMap.getWidth()/2,
546 paletteMap,
547 "^(w+)b(p+)b(w+)$",
548 true
549 );
550
551 // (within a tolerance for numerical error) the number of pixels on the top of the viewport marker
552 // should equal the number on the bottom
553 assertTrue(
554 Math.abs(colMatcher.group(1).length() - colMatcher.group(3).length()) < 4,
555 "Viewport marker not vertically centered"
556 );
557
558 // (within a tolerance for numerical error) the viewport marker should be square
559 assertTrue(
560 Math.abs(colMatcher.group(2).length() - rowMatcher.group(2).length()) < 4,
561 "Viewport marker not square"
562 );
563
564 // now change the mapView size
565 GuiHelper.runInEDTAndWaitWithException(() -> {
566 mapView.setBounds(0, 0, 150, 300);
567 Arrays.stream(mapView.getComponentListeners()).forEach(
568 cl -> cl.componentResized(new ComponentEvent(mapView, ComponentEvent.COMPONENT_RESIZED))
569 );
570 });
571 // minimap doesn't (yet?) listen for component resize events to update its viewport marker, so
572 // trigger a zoom change
573 mapView.zoomTo(mapView.getCenter().add(1., 0.));
574 this.paintSlippyMap();
575
576 rowMatcher = ImagePatternMatching.rowMatch(
577 paintedSlippyMap,
578 paintedSlippyMap.getHeight()/2,
579 paletteMap,
580 "^(w+)b(p+)b(w+)$",
581 true
582 );
583 assertTrue(
584 Math.abs(rowMatcher.group(1).length() - rowMatcher.group(3).length()) < 4,
585 "Viewport marker not horizontally centered"
586 );
587
588 colMatcher = ImagePatternMatching.columnMatch(
589 paintedSlippyMap,
590 paintedSlippyMap.getWidth()/2,
591 paletteMap,
592 "^(w+)b(p+)b(w+)$",
593 true
594 );
595 assertTrue(
596 Math.abs(colMatcher.group(1).length() - colMatcher.group(3).length()) < 4,
597 "Viewport marker not vertically centered"
598 );
599
600 try {
601 javax.imageio.ImageIO.write(paintedSlippyMap, "png", new java.io.File("failed.png"));
602 } catch (java.io.IOException ioe) {
603 System.err.println("Failed writing image");
604 }
605
606 assertTrue(
607 Math.abs(colMatcher.group(2).length() - (rowMatcher.group(2).length()*2.0)) < 5,
608 "Viewport marker not 2:1 aspect ratio"
609 );
610 }
611
612 protected JCheckBoxMenuItem getShowDownloadedAreaMenuItem() {
613 JPopupMenu menu = this.sourceButton.getPopupMenu();
614 boolean afterSeparator = false;
615 for (Component c: menu.getComponents()) {
616 if (c instanceof JPopupMenu.Separator) {
617 assertFalse(afterSeparator, "More than one separator before target item");
618 afterSeparator = true;
619 } else if (((JMenuItem) c).getText().equals(tr("Show downloaded area"))) {
620 assertTrue(afterSeparator, "Separator not found before target item");
621 return assertInstanceOf(JCheckBoxMenuItem.class, c, "Target item doesn't appear to be a JCheckBoxMenuItem");
622 }
623 }
624 fail("'Show downloaded area' menu item not found");
625 return null;
626 }
627
628 /**
629 * test downloaded area is shown shaded
630 */
631 @Test
632 void testShowDownloadedArea() {
633 Config.getPref().put("slippy_map_chooser.mapstyle", "Green Tiles");
634 Config.getPref().putBoolean("slippy_map_chooser.show_downloaded_area", false);
635
636 DataSet dataSet = new DataSet();
637 dataSet.addDataSource(new DataSource(new Bounds(51.725, -0.0209, 51.746, 0.0162), "Somewhere"));
638
639 OsmDataLayer dataLayer = new OsmDataLayer(
640 dataSet,
641 "Test Layer 123",
642 null
643 );
644 MainApplication.getLayerManager().addLayer(dataLayer);
645 MainApplication.getLayerManager().setActiveLayer(dataLayer);
646
647 MapView mapView = MainApplication.getMap().mapView;
648 GuiHelper.runInEDTAndWaitWithException(() -> {
649 mapView.setVisible(true);
650 mapView.addNotify();
651 mapView.doLayout();
652 mapView.setBounds(0, 0, 500, 500);
653 });
654
655 this.setUpMiniMap();
656
657 // assert "show downloaded areas" checkbox is unchecked
658 assertFalse(this.getShowDownloadedAreaMenuItem().isSelected());
659
660 // we won't end up with exactly this viewport as it doesn't *precisely* match the aspect ratio
661 mapView.zoomTo(new Bounds(51.732, -0.0269, 51.753, 0.0102));
662
663 // an initial paint operation is required to trigger the tile fetches
664 this.paintSlippyMap();
665
666 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
667
668 this.paintSlippyMap();
669
670 Map<Integer, String> paletteMap = new HashMap<Integer, String>() {{
671 put(0xff00ff00, "g"); // green
672 put(0xff000000, "b"); // black
673 put(0xff8ad16b, "v"); // viewport marker inner (pink+green mix)
674 put(0xff00df00, "d"); // (shaded green)
675 put(0xff8ac46b, "q"); // (shaded pink+green mix)
676 }};
677
678 // assert downloaded areas are not drawn
679 ImagePatternMatching.rowMatch(
680 paintedSlippyMap,
681 paintedSlippyMap.getHeight()/2,
682 paletteMap,
683 "^g+bv+bg+$",
684 true
685 );
686 ImagePatternMatching.columnMatch(
687 paintedSlippyMap,
688 paintedSlippyMap.getWidth()/2,
689 paletteMap,
690 "^g+bv+bg+$",
691 true
692 );
693
694 // enable "show downloaded areas"
695 GuiHelper.runInEDTAndWaitWithException(() -> this.getShowDownloadedAreaMenuItem().doClick());
696 assertTrue(this.getShowDownloadedAreaMenuItem().isSelected());
697
698 // assert downloaded areas are drawn
699 this.paintSlippyMap();
700
701 ImagePatternMatching.rowMatch(
702 paintedSlippyMap,
703 paintedSlippyMap.getHeight()/2,
704 paletteMap,
705 "^d+bq+v+bg+d+$",
706 true
707 );
708 ImagePatternMatching.columnMatch(
709 paintedSlippyMap,
710 paintedSlippyMap.getWidth()/2,
711 paletteMap,
712 "^d+bq+v+bg+d+$",
713 true
714 );
715
716 // also assert the leftmost column doesn't (yet) have any downloaded area marks (i.e. fully shaded)
717 ImagePatternMatching.columnMatch(
718 paintedSlippyMap,
719 0,
720 paletteMap,
721 "^d+$",
722 true
723 );
724
725 // add another downloaded area, going off the left of the widget
726 dataSet.addDataSource(new DataSource(new Bounds(51.745, -1., 51.765, 0.0162), "Somewhere else"));
727 // and redraw
728 this.paintSlippyMap();
729
730 // the middle row should be as before
731 ImagePatternMatching.rowMatch(
732 paintedSlippyMap,
733 paintedSlippyMap.getHeight()/2,
734 paletteMap,
735 "^d+bq+v+bg+d+$",
736 true
737 );
738 // the middle column should have its unshaded region extended beyond the viewport marker
739 ImagePatternMatching.columnMatch(
740 paintedSlippyMap,
741 paintedSlippyMap.getWidth()/2,
742 paletteMap,
743 "^d+g+bv+bg+d+$",
744 true
745 );
746 // but the leftmost column should now have an unshaded mark
747 ImagePatternMatching.columnMatch(
748 paintedSlippyMap,
749 0,
750 paletteMap,
751 "^d+g+d+$",
752 true
753 );
754 // and the rightmost column should be untouched
755 ImagePatternMatching.columnMatch(
756 paintedSlippyMap,
757 paintedSlippyMap.getWidth()-1,
758 paletteMap,
759 "^d+$",
760 true
761 );
762
763 // and now if we pan to the left (in EastNorth units)
764 mapView.zoomTo(mapView.getCenter().add(-5000., 0.));
765 // and redraw
766 this.paintSlippyMap();
767
768 // the middle row should have its unshaded region outside the viewport marker
769 ImagePatternMatching.rowMatch(
770 paintedSlippyMap,
771 paintedSlippyMap.getHeight()/2,
772 paletteMap,
773 "^d+bq+bd+g+d*$",
774 true
775 );
776 // the middle column should have a shaded region inside the viewport marker
777 ImagePatternMatching.columnMatch(
778 paintedSlippyMap,
779 paintedSlippyMap.getWidth()/2,
780 paletteMap,
781 "^d+g+bv+q+bd+$",
782 true
783 );
784 }
785
786 /**
787 * test display of downloaded area follows active layer switching
788 */
789 @Test
790 void testShowDownloadedAreaLayerSwitching() {
791 Config.getPref().put("slippy_map_chooser.mapstyle", "Green Tiles");
792 Config.getPref().putBoolean("slippy_map_chooser.show_downloaded_area", true);
793
794 DataSet dataSetA = new DataSet();
795 // dataSetA has a long thin horizontal downloaded area (extending off the left & right of the map)
796 dataSetA.addDataSource(new DataSource(new Bounds(-18., -61.02, -15., -60.98), "Elsewhere"));
797
798 OsmDataLayer dataLayerA = new OsmDataLayer(
799 dataSetA,
800 "Test Layer A",
801 null
802 );
803 MainApplication.getLayerManager().addLayer(dataLayerA);
804
805 DataSet dataSetB = new DataSet();
806 // dataSetB has a long thin vertical downloaded area (extending off the top & bottom of the map)
807 dataSetB.addDataSource(new DataSource(new Bounds(-16.38, -62., -16.34, -60.), "Nowhere"));
808
809 OsmDataLayer dataLayerB = new OsmDataLayer(
810 dataSetB,
811 "Test Layer B",
812 null
813 );
814 MainApplication.getLayerManager().addLayer(dataLayerB);
815
816 MainApplication.getLayerManager().setActiveLayer(dataLayerB);
817
818 MapView mapView = MainApplication.getMap().mapView;
819 GuiHelper.runInEDTAndWaitWithException(() -> {
820 mapView.setVisible(true);
821 mapView.addNotify();
822 mapView.doLayout();
823 mapView.setBounds(0, 0, 400, 400);
824 });
825
826 this.setUpMiniMap();
827
828 // assert "show downloaded areas" checkbox is checked
829 assertTrue(this.getShowDownloadedAreaMenuItem().isSelected());
830
831 // again, we won't end up with exactly this viewport as it doesn't *precisely* match the aspect ratio
832 mapView.zoomTo(new Bounds(-16.423, -61.076, -16.299, -60.932));
833
834 // an initial paint operation is required to trigger the tile fetches
835 this.paintSlippyMap();
836
837 Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
838
839 this.paintSlippyMap();
840
841 Map<Integer, String> paletteMap = new HashMap<Integer, String>() {{
842 put(0xff00ff00, "g"); // green
843 put(0xff000000, "b"); // black
844 put(0xff8ad16b, "v"); // viewport marker inner (pink+green mix)
845 put(0xff00df00, "d"); // (shaded green)
846 put(0xff8ac46b, "q"); // (shaded pink+green mix)
847 }};
848
849 // the middle row should be entirely unshaded
850 ImagePatternMatching.rowMatch(
851 paintedSlippyMap,
852 paintedSlippyMap.getHeight()/2,
853 paletteMap,
854 "^g+bv+bg+$",
855 true
856 );
857 // the middle column should have an unshaded band within the viewport marker
858 Matcher centerMatcher = ImagePatternMatching.columnMatch(
859 paintedSlippyMap,
860 paintedSlippyMap.getWidth()/2,
861 paletteMap,
862 "^(d+bq+)(v+)(q+bd+)$",
863 true
864 );
865 // the leftmost and rightmost columns should have an unshaded band
866 Matcher leftMatcher = ImagePatternMatching.columnMatch(
867 paintedSlippyMap,
868 0,
869 paletteMap,
870 "^(d+)(g+)(d+)$",
871 true
872 );
873 Matcher rightMatcher = ImagePatternMatching.columnMatch(
874 paintedSlippyMap,
875 paintedSlippyMap.getWidth()-1,
876 paletteMap,
877 "^(d+)(g+)(d+)$",
878 true
879 );
880 // the three columns should have the unshaded band in the same place
881 assertEquals(centerMatcher.group(1).length(), leftMatcher.group(1).length());
882 assertEquals(centerMatcher.group(1).length(), rightMatcher.group(1).length());
883 assertEquals(centerMatcher.group(2).length(), leftMatcher.group(2).length());
884 assertEquals(centerMatcher.group(2).length(), rightMatcher.group(2).length());
885
886 // switch active layer
887 MainApplication.getLayerManager().setActiveLayer(dataLayerA);
888 this.paintSlippyMap();
889
890 // the middle column should be entirely unshaded
891 ImagePatternMatching.columnMatch(
892 paintedSlippyMap,
893 paintedSlippyMap.getWidth()/2,
894 paletteMap,
895 "^g+bv+bg+$",
896 true
897 );
898 // the middle row should have an unshaded band within the viewport marker
899 centerMatcher = ImagePatternMatching.rowMatch(
900 paintedSlippyMap,
901 paintedSlippyMap.getHeight()/2,
902 paletteMap,
903 "^(d+bq+)(v+)(q+bd+)$",
904 true
905 );
906 // the topmost and bottommost rows should have an unshaded band
907 Matcher topMatcher = ImagePatternMatching.rowMatch(
908 paintedSlippyMap,
909 0,
910 paletteMap,
911 "^(d+)(g+)(d+)$",
912 true
913 );
914 Matcher BottomMatcher = ImagePatternMatching.rowMatch(
915 paintedSlippyMap,
916 paintedSlippyMap.getHeight()-1,
917 paletteMap,
918 "^(d+)(g+)(d+)$",
919 true
920 );
921 // the three rows should have the unshaded band in the same place
922 assertEquals(centerMatcher.group(1).length(), topMatcher.group(1).length());
923 assertEquals(centerMatcher.group(1).length(), BottomMatcher.group(1).length());
924 assertEquals(centerMatcher.group(2).length(), topMatcher.group(2).length());
925 assertEquals(centerMatcher.group(2).length(), BottomMatcher.group(2).length());
926
927 // deleting dataLayerA should hopefully switch our active layer back to dataLayerB
928 MainApplication.getLayerManager().removeLayer(dataLayerA);
929 this.paintSlippyMap();
930
931 // now we're really just repeating the same assertions we made originally when dataLayerB was active
932 // the middle row should be entirely unshaded
933 ImagePatternMatching.rowMatch(
934 paintedSlippyMap,
935 paintedSlippyMap.getHeight()/2,
936 paletteMap,
937 "^g+bv+bg+$",
938 true
939 );
940 // the middle column should have an unshaded band within the viewport marker
941 centerMatcher = ImagePatternMatching.columnMatch(
942 paintedSlippyMap,
943 paintedSlippyMap.getWidth()/2,
944 paletteMap,
945 "^(d+bq+)(v+)(q+bd+)$",
946 true
947 );
948 // the leftmost and rightmost columns should have an unshaded band
949 leftMatcher = ImagePatternMatching.columnMatch(
950 paintedSlippyMap,
951 0,
952 paletteMap,
953 "^(d+)(g+)(d+)$",
954 true
955 );
956 rightMatcher = ImagePatternMatching.columnMatch(
957 paintedSlippyMap,
958 paintedSlippyMap.getWidth()-1,
959 paletteMap,
960 "^(d+)(g+)(d+)$",
961 true
962 );
963 // the three columns should have the unshaded band in the same place
964 assertEquals(centerMatcher.group(1).length(), leftMatcher.group(1).length());
965 assertEquals(centerMatcher.group(1).length(), rightMatcher.group(1).length());
966 assertEquals(centerMatcher.group(2).length(), leftMatcher.group(2).length());
967 assertEquals(centerMatcher.group(2).length(), rightMatcher.group(2).length());
968
969 // but now if we expand its downloaded area to cover most of the southern hemisphere...
970 dataSetB.addDataSource(new DataSource(new Bounds(-75., -100., 0., 100.), "Everywhere"));
971 this.paintSlippyMap();
972
973 // we should see it all as unshaded.
974 ImagePatternMatching.rowMatch(
975 paintedSlippyMap,
976 0,
977 paletteMap,
978 "^g+$",
979 true
980 );
981 ImagePatternMatching.rowMatch(
982 paintedSlippyMap,
983 paintedSlippyMap.getHeight()/2,
984 paletteMap,
985 "^g+bv+bg+$",
986 true
987 );
988 ImagePatternMatching.rowMatch(
989 paintedSlippyMap,
990 paintedSlippyMap.getHeight()-1,
991 paletteMap,
992 "^g+$",
993 true
994 );
995 ImagePatternMatching.columnMatch(
996 paintedSlippyMap,
997 0,
998 paletteMap,
999 "^g+$",
1000 true
1001 );
1002 ImagePatternMatching.columnMatch(
1003 paintedSlippyMap,
1004 paintedSlippyMap.getWidth()/2,
1005 paletteMap,
1006 "^g+bv+bg+$",
1007 true
1008 );
1009 ImagePatternMatching.columnMatch(
1010 paintedSlippyMap,
1011 paintedSlippyMap.getWidth()-1,
1012 paletteMap,
1013 "^g+$",
1014 true
1015 );
1016 }
1017}
Note: See TracBrowser for help on using the repository browser.