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

Last change on this file since 11776 was 11776, checked in by michael2402, 7 years ago

Reduce startup time of StyleCacheTest, use test rules, do not leak memory. See #14495

  • Property svn:eol-style set to native
File size: 6.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import static org.junit.Assert.assertEquals;
5
6import java.awt.Color;
7import java.awt.Graphics2D;
8import java.awt.image.BufferedImage;
9import java.io.File;
10import java.io.InputStream;
11import java.util.IdentityHashMap;
12
13import org.junit.AfterClass;
14import org.junit.Assert;
15import org.junit.Before;
16import org.junit.BeforeClass;
17import org.junit.Rule;
18import org.junit.Test;
19import org.openstreetmap.josm.JOSMFixture;
20import org.openstreetmap.josm.Main;
21import org.openstreetmap.josm.data.Bounds;
22import org.openstreetmap.josm.data.osm.DataSet;
23import org.openstreetmap.josm.data.osm.OsmPrimitive;
24import org.openstreetmap.josm.data.osm.visitor.paint.Rendering;
25import org.openstreetmap.josm.data.osm.visitor.paint.StyledMapRenderer;
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 */
39public class 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 @Rule
54 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
55 public JOSMTestRules test = new JOSMTestRules().preferences().platform().projection();
56
57 /**
58 * Load the test data that is required.
59 * @throws Exception
60 */
61 @BeforeClass
62 public static void load() throws Exception {
63 img = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_ARGB);
64
65 try (
66 InputStream fisC = Compression.getUncompressedFileInputStream(new File("data_nodist/neubrandenburg.osm.bz2"));
67 ) {
68 dsCity = OsmReader.parseDataSet(fisC, NullProgressMonitor.INSTANCE);
69 }
70 dsCity2 = new DataSet(dsCity);
71 }
72
73 /**
74 * Free the memory allocated for this test.
75 * <p>
76 * Since we are running junit in non-forked mode, we don't know when this test will not be referenced any more.
77 */
78 @AfterClass
79 public static void unload() {
80 g = null;
81 img = null;
82 nc = null;
83 dsCity = null;
84 dsCity2 = null;
85 }
86
87 /**
88 * Create the temporary graphics
89 */
90 @Before
91 public void loadGraphicComponents() {
92 g = (Graphics2D) img.getGraphics();
93 g.setClip(0, 0, IMG_WIDTH, IMG_WIDTH);
94 g.setColor(Color.BLACK);
95 g.fillRect(0, 0, IMG_WIDTH, IMG_WIDTH);
96 nc = new MapView(Main.getLayerManager(), null);
97 nc.setBounds(0, 0, IMG_WIDTH, IMG_HEIGHT);
98 MapPaintStyles.readFromPreferences();
99 }
100
101 /**
102 * Verifies, that the intern pool is not growing when repeatedly rendering the
103 * same set of primitives (and clearing the calculated styles each time).
104 *
105 * If it grows, this is an indication that the {@code equals} and {@code hashCode}
106 * implementation is broken and two identical objects are not recognized as equal
107 * or produce different hash codes.
108 *
109 * The opposite problem (different objects are mistaken as equal) has more visible
110 * consequences for the user (wrong rendering on the map) and is not recognized by
111 * this test.
112 */
113 @Test
114 public void testStyleCacheInternPool() {
115 // This can be removed if there was no dependency on Main.map in some MapCSS conditions. See #14572
116 JOSMFixture.createFunctionalTestFixture().init(true);
117
118 Bounds bounds = new Bounds(53.56, 13.25, 53.57, 13.26);
119 Rendering visitor = new StyledMapRenderer(g, nc, false);
120 nc.zoomTo(bounds);
121 Integer internPoolSize = null;
122 for (int i = 0; i < 10; i++) {
123 visitor.render(dsCity, true, bounds);
124 MapPaintStyles.getStyles().clearCached();
125 int newInternPoolSize = StyleCache.getInternPoolSize();
126 if (internPoolSize == null) {
127 internPoolSize = newInternPoolSize;
128 } else {
129 assertEquals("intern pool size", internPoolSize.intValue(), newInternPoolSize);
130 }
131 }
132 }
133
134 /**
135 * Verifies, that the number of {@code StyleElementList} instances stored
136 * for all the rendered primitives is actually low (as intended).
137 *
138 * Two primitives with the same style should share one {@code StyleElementList}
139 * instance for the cached style elements. This is verified by counting all
140 * the instances using {@code A == B} identity.
141 */
142 @Test
143 public void testStyleCacheInternPool2() {
144 // This can be removed if there was no dependency on Main.map in some MapCSS conditions. See #14572
145 JOSMFixture.createFunctionalTestFixture().init(true);
146
147 Bounds bounds = new Bounds(53.56, 13.25, 53.57, 13.26);
148 Rendering visitor = new StyledMapRenderer(g, nc, false);
149 nc.zoomTo(bounds);
150 visitor.render(dsCity2, true, bounds);
151
152 IdentityHashMap<StyleElementList, Integer> counter = new IdentityHashMap<>();
153 int noPrimitives = 0;
154 for (OsmPrimitive osm : dsCity2.allPrimitives()) {
155 // primitives, that have been rendered, should have the cache populated
156 if (osm.mappaintStyle != null) {
157 noPrimitives++;
158 Pair<StyleElementList, Range> p = osm.mappaintStyle.getWithRange(nc.getDist100Pixel(), false);
159 StyleElementList sel = p.a;
160 Assert.assertNotNull(sel);
161 Integer k = counter.get(sel);
162 if (k == null) {
163 k = 0;
164 }
165 counter.put(sel, k + 1);
166 }
167 }
168 int EXPECTED_NO_PRIMITIVES = 4294; // needs to be updated if data file or bbox changes
169 Assert.assertEquals(
170 "The number of rendered primitives should be " + EXPECTED_NO_PRIMITIVES,
171 EXPECTED_NO_PRIMITIVES, noPrimitives);
172 Assert.assertTrue(
173 "Too many StyleElementList instances, they should be shared using the StyleCache",
174 counter.size() < 100);
175 }
176}
Note: See TracBrowser for help on using the repository browser.