source: josm/trunk/test/functional/org/openstreetmap/josm/gui/mappaint/StyleCacheTest.java@ 17625

Last change on this file since 17625 was 17625, checked in by simon04, 3 years ago

see #4626 - Fix StyleCacheTest (cannot use PerformanceTestUtils)

  • Property svn:eol-style set to native
File size: 6.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import static org.junit.jupiter.api.Assertions.assertEquals;
5import static org.junit.jupiter.api.Assertions.assertNotNull;
6import static org.junit.jupiter.api.Assertions.assertTrue;
7
8import java.awt.Color;
9import java.awt.Graphics2D;
10import java.awt.image.BufferedImage;
11import java.io.File;
12import java.io.InputStream;
13import java.util.IdentityHashMap;
14
15import org.junit.jupiter.api.AfterAll;
16import org.junit.jupiter.api.BeforeAll;
17import org.junit.jupiter.api.BeforeEach;
18import org.junit.jupiter.api.Test;
19import org.junit.jupiter.api.extension.RegisterExtension;
20import org.openstreetmap.josm.data.Bounds;
21import org.openstreetmap.josm.data.osm.DataSet;
22import org.openstreetmap.josm.data.osm.OsmPrimitive;
23import org.openstreetmap.josm.data.osm.visitor.paint.Rendering;
24import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
25import org.openstreetmap.josm.gui.MainApplication;
26import org.openstreetmap.josm.gui.MapView;
27import org.openstreetmap.josm.gui.NavigatableComponent;
28import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
29import org.openstreetmap.josm.io.Compression;
30import org.openstreetmap.josm.io.OsmReader;
31import org.openstreetmap.josm.testutils.JOSMTestRules;
32import org.openstreetmap.josm.tools.Pair;
33
34import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35
36/**
37 * Test {@link StyleCache}.
38 */
39class StyleCacheTest {
40
41 private static final int IMG_WIDTH = 1400;
42 private static final int IMG_HEIGHT = 1050;
43
44 private static Graphics2D g;
45 private static BufferedImage img;
46 private static NavigatableComponent nc;
47 private static DataSet dsCity;
48 private static DataSet dsCity2;
49
50 /**
51 * The test rules used for this test.
52 */
53 @RegisterExtension
54 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
55 public JOSMTestRules test = new JOSMTestRules().preferences().projection().mapStyles().timeout(60000);
56
57 /**
58 * Load the test data that is required.
59 * @throws Exception If an error occurred during load.
60 */
61 @BeforeAll
62 public static void load() throws Exception {
63 img = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_ARGB);
64 try (InputStream in = Compression.getUncompressedFileInputStream(new File("nodist/data/neubrandenburg.osm.bz2"))) {
65 dsCity = OsmReader.parseDataSet(in, NullProgressMonitor.INSTANCE);
66 }
67 dsCity2 = new DataSet(dsCity);
68 }
69
70 /**
71 * Free the memory allocated for this test.
72 * <p>
73 * Since we are running junit in non-forked mode, we don't know when this test will not be referenced any more.
74 */
75 @AfterAll
76 public static void unload() {
77 g = null;
78 img = null;
79 nc = null;
80 dsCity = null;
81 dsCity2 = null;
82 }
83
84 /**
85 * Create the temporary graphics
86 */
87 @BeforeEach
88 public void loadGraphicComponents() {
89 g = (Graphics2D) img.getGraphics();
90 g.setClip(0, 0, IMG_WIDTH, IMG_WIDTH);
91 g.setColor(Color.BLACK);
92 g.fillRect(0, 0, IMG_WIDTH, IMG_WIDTH);
93 nc = new MapView(MainApplication.getLayerManager(), null);
94 nc.setBounds(0, 0, IMG_WIDTH, IMG_HEIGHT);
95 }
96
97 /**
98 * Verifies, that the intern pool is not growing when repeatedly rendering the
99 * same set of primitives (and clearing the calculated styles each time).
100 *
101 * If it grows, this is an indication that the {@code equals} and {@code hashCode}
102 * implementation is broken and two identical objects are not recognized as equal
103 * or produce different hash codes.
104 *
105 * The opposite problem (different objects are mistaken as equal) has more visible
106 * consequences for the user (wrong rendering on the map) and is not recognized by
107 * this test.
108 */
109 @Test
110 void testStyleCacheInternPool() {
111 MapPaintStyles.getStyles().clearCached();
112 StyleCache.clearStyleCachePool();
113 Bounds bounds = new Bounds(53.56, 13.25, 53.57, 13.26);
114 Rendering visitor = new StyledMapRenderer(g, nc, false);
115 nc.zoomTo(bounds);
116 Integer internPoolSize = null;
117 for (int i = 0; i < 10; i++) {
118 visitor.render(dsCity, true, bounds);
119 MapPaintStyles.getStyles().clearCached();
120 int newInternPoolSize = StyleCache.getInternPoolSize();
121 if (internPoolSize == null) {
122 internPoolSize = newInternPoolSize;
123 } else {
124 if (internPoolSize != newInternPoolSize) {
125 System.err.println("style sources:");
126 for (StyleSource s : MapPaintStyles.getStyles().getStyleSources()) {
127 System.err.println(s.url + " active:" + s.active);
128 }
129 }
130 assertEquals(internPoolSize.intValue(), newInternPoolSize, "intern pool size");
131 }
132 }
133 }
134
135 /**
136 * Verifies, that the number of {@code StyleElementList} instances stored
137 * for all the rendered primitives is actually low (as intended).
138 *
139 * Two primitives with the same style should share one {@code StyleElementList}
140 * instance for the cached style elements. This is verified by counting all
141 * the instances using {@code A == B} identity.
142 */
143 @Test
144 void testStyleCacheInternPool2() {
145 StyleCache.clearStyleCachePool();
146 Bounds bounds = new Bounds(53.56, 13.25, 53.57, 13.26);
147 Rendering visitor = new StyledMapRenderer(g, nc, false);
148 nc.zoomTo(bounds);
149 visitor.render(dsCity2, true, bounds);
150
151 IdentityHashMap<StyleElementList, Integer> counter = new IdentityHashMap<>();
152 int noPrimitives = 0;
153 for (OsmPrimitive osm : dsCity2.allPrimitives()) {
154 // primitives, that have been rendered, should have the cache populated
155 if (osm.getCachedStyle() != null) {
156 noPrimitives++;
157 Pair<StyleElementList, Range> p = osm.getCachedStyle().getWithRange(nc.getDist100Pixel(), false);
158 StyleElementList sel = p.a;
159 assertNotNull(sel);
160 Integer k = counter.get(sel);
161 if (k == null) {
162 k = 0;
163 }
164 counter.put(sel, k + 1);
165 }
166 }
167 int EXPECTED_NO_PRIMITIVES = 4294; // needs to be updated if data file or bbox changes
168 assertEquals(EXPECTED_NO_PRIMITIVES, noPrimitives,
169 "The number of rendered primitives should be " + EXPECTED_NO_PRIMITIVES);
170 assertTrue(counter.size() < 100,
171 "Too many StyleElementList instances, they should be shared using the StyleCache");
172 }
173}
Note: See TracBrowser for help on using the repository browser.