source: josm/trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.groovy@ 8494

Last change on this file since 8494 was 8494, checked in by simon04, 9 years ago

see #11150 - MapCSS: refactor pseudo classes to factory based instantiation; consider :sameTags, :same-tags, :same_tags equivalent

  • Property svn:eol-style set to native
File size: 18.1 KB
Line 
1package org.openstreetmap.josm.gui.mappaint.mapcss
2
3import java.awt.Color
4
5import org.junit.Before
6import org.junit.Test
7import org.openstreetmap.josm.JOSMFixture
8import org.openstreetmap.josm.Main
9import org.openstreetmap.josm.data.coor.LatLon
10import org.openstreetmap.josm.data.osm.DataSet
11import org.openstreetmap.josm.data.osm.OsmUtils
12import org.openstreetmap.josm.data.osm.Way
13import org.openstreetmap.josm.gui.mappaint.Environment
14import org.openstreetmap.josm.gui.mappaint.MultiCascade
15import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser
16import org.openstreetmap.josm.tools.ColorHelper
17
18class MapCSSParserTest {
19
20 protected static Environment getEnvironment(String key, String value) {
21 return new Environment(OsmUtils.createPrimitive("way " + key + "=" + value))
22 }
23
24 protected static MapCSSParser getParser(String stringToParse) {
25 return new MapCSSParser(new StringReader(stringToParse));
26 }
27
28 @Before
29 public void setUp() throws Exception {
30 JOSMFixture.createUnitTestFixture().init();
31 }
32
33 @Test
34 public void testKothicStylesheets() throws Exception {
35 new MapCSSParser(new URL("http://kothic.googlecode.com/hg/src/styles/default.mapcss").openStream(), "UTF-8")
36 new MapCSSParser(new URL("http://kothic.googlecode.com/hg/src/styles/mapink.mapcss").openStream(), "UTF-8")
37 }
38
39 @Test
40 public void testDeclarations() {
41 getParser("{ opacity: 0.5; color: rgb(1.0, 0.0, 0.0); }").declaration()
42 getParser("{ set tag=value; }").declaration() //set a tag
43 getParser("{ set tag; }").declaration() // set a tag to 'yes'
44 getParser("{ opacity: eval(\"tag('population')/100000\"); }").declaration()
45 getParser("{ set width_in_metres=eval(\"tag('lanes')*3\"); }").declaration()
46 }
47
48 @Test
49 public void testClassCondition() throws Exception {
50 def conditions = ((Selector.GeneralSelector) getParser("way[name=X].highway:closed").selector()).conds
51 assert conditions.get(0) instanceof Condition.SimpleKeyValueCondition
52 assert conditions.get(0).applies(getEnvironment("name", "X"))
53 assert conditions.get(1) instanceof Condition.ClassCondition
54 assert conditions.get(2) instanceof Condition.PseudoClassCondition
55 assert !conditions.get(2).applies(getEnvironment("name", "X"))
56 }
57
58 @Test
59 public void testPseudoClassCondition() throws Exception {
60 def c1 = ((Selector.GeneralSelector) getParser("way!:area-style").selector()).conds.get(0)
61 def c2 = ((Selector.GeneralSelector) getParser("way!:areaStyle").selector()).conds.get(0)
62 def c3 = ((Selector.GeneralSelector) getParser("way!:area_style").selector()).conds.get(0)
63 assert c1.toString() == "!:areaStyle"
64 assert c2.toString() == "!:areaStyle"
65 assert c3.toString() == "!:areaStyle"
66 }
67
68 @Test
69 public void testClassMatching() throws Exception {
70 def css = new MapCSSStyleSource("" +
71 "way[highway=footway] { set .path; color: #FF6644; width: 2; }\n" +
72 "way[highway=path] { set path; color: brown; width: 2; }\n" +
73 "way[\"set\"=escape] { }\n" +
74 "way.path { text:auto; text-color: green; text-position: line; text-offset: 5; }\n" +
75 "way!.path { color: orange; }\n"
76 )
77 css.loadStyleSource()
78 assert css.getErrors().isEmpty()
79 def mc1 = new MultiCascade()
80 css.apply(mc1, OsmUtils.createPrimitive("way highway=path"), 1, false);
81 assert "green".equals(mc1.getCascade("default").get("text-color", null, String.class))
82 assert "brown".equals(mc1.getCascade("default").get("color", null, String.class))
83 def mc2 = new MultiCascade()
84 css.apply(mc2, OsmUtils.createPrimitive("way highway=residential"), 1, false);
85 assert "orange".equals(mc2.getCascade("default").get("color", null, String.class))
86 assert mc2.getCascade("default").get("text-color", null, String.class) == null
87 def mc3 = new MultiCascade()
88 css.apply(mc3, OsmUtils.createPrimitive("way highway=footway"), 1, false);
89 assert ColorHelper.html2color("#FF6644").equals(mc3.getCascade("default").get("color", null, Color.class))
90 }
91
92 @Test
93 public void testEqualCondition() throws Exception {
94 def condition = (Condition.SimpleKeyValueCondition) getParser("[surface=paved]").condition(Condition.Context.PRIMITIVE)
95 assert condition instanceof Condition.SimpleKeyValueCondition
96 assert "surface".equals(condition.k)
97 assert "paved".equals(condition.v)
98 assert condition.applies(getEnvironment("surface", "paved"))
99 assert !condition.applies(getEnvironment("surface", "unpaved"))
100 }
101
102 @Test
103 public void testNotEqualCondition() throws Exception {
104 def condition = (Condition.KeyValueCondition) getParser("[surface!=paved]").condition(Condition.Context.PRIMITIVE)
105 assert Condition.Op.NEQ.equals(condition.op)
106 assert !condition.applies(getEnvironment("surface", "paved"))
107 assert condition.applies(getEnvironment("surface", "unpaved"))
108 }
109
110 @Test
111 public void testRegexCondition() throws Exception {
112 def condition = (Condition.KeyValueCondition) getParser("[surface=~/paved|unpaved/]").condition(Condition.Context.PRIMITIVE)
113 assert Condition.Op.REGEX.equals(condition.op)
114 assert condition.applies(getEnvironment("surface", "unpaved"))
115 assert !condition.applies(getEnvironment("surface", "grass"))
116 }
117
118 @Test
119 public void testRegexConditionParenthesis() throws Exception {
120 def condition = (Condition.KeyValueCondition) getParser("[name =~ /^\\(foo\\)/]").condition(Condition.Context.PRIMITIVE)
121 assert condition.applies(getEnvironment("name", "(foo)"))
122 assert !condition.applies(getEnvironment("name", "foo"))
123 assert !condition.applies(getEnvironment("name", "((foo))"))
124 }
125
126 @Test
127 public void testNegatedRegexCondition() throws Exception {
128 def condition = (Condition.KeyValueCondition) getParser("[surface!~/paved|unpaved/]").condition(Condition.Context.PRIMITIVE)
129 assert Condition.Op.NREGEX.equals(condition.op)
130 assert !condition.applies(getEnvironment("surface", "unpaved"))
131 assert condition.applies(getEnvironment("surface", "grass"))
132 }
133
134 @Test
135 public void testBeginsEndsWithCondition() throws Exception {
136 def condition = (Condition.KeyValueCondition) getParser('[foo ^= bar]').condition(Condition.Context.PRIMITIVE)
137 assert Condition.Op.BEGINS_WITH.equals(condition.op)
138 assert condition.applies(getEnvironment("foo", "bar123"))
139 assert !condition.applies(getEnvironment("foo", "123bar"))
140 assert !condition.applies(getEnvironment("foo", "123bar123"))
141 condition = (Condition.KeyValueCondition) getParser('[foo $= bar]').condition(Condition.Context.PRIMITIVE)
142 assert Condition.Op.ENDS_WITH.equals(condition.op)
143 assert !condition.applies(getEnvironment("foo", "bar123"))
144 assert condition.applies(getEnvironment("foo", "123bar"))
145 assert !condition.applies(getEnvironment("foo", "123bar123"))
146 }
147
148 @Test
149 public void testOneOfCondition() throws Exception {
150 def condition = getParser('[vending~=stamps]').condition(Condition.Context.PRIMITIVE)
151 assert condition.applies(getEnvironment("vending", "stamps"))
152 assert condition.applies(getEnvironment("vending", "bar;stamps;foo"))
153 assert !condition.applies(getEnvironment("vending", "every;thing;else"))
154 assert !condition.applies(getEnvironment("vending", "or_nothing"))
155 }
156
157 @Test
158 public void testStandardKeyCondition() throws Exception {
159 def c1 = (Condition.KeyCondition) getParser("[ highway ]").condition(Condition.Context.PRIMITIVE)
160 assert c1.matchType == null
161 assert c1.applies(getEnvironment("highway", "unclassified"))
162 assert !c1.applies(getEnvironment("railway", "rail"))
163 def c2 = (Condition.KeyCondition) getParser("[\"/slash/\"]").condition(Condition.Context.PRIMITIVE)
164 assert c2.matchType == null
165 assert c2.applies(getEnvironment("/slash/", "yes"))
166 assert !c2.applies(getEnvironment("\"slash\"", "no"))
167 }
168
169 @Test
170 public void testYesNoKeyCondition() throws Exception {
171 def c1 = (Condition.KeyCondition) getParser("[oneway?]").condition(Condition.Context.PRIMITIVE)
172 def c2 = (Condition.KeyCondition) getParser("[oneway?!]").condition(Condition.Context.PRIMITIVE)
173 def c3 = (Condition.KeyCondition) getParser("[!oneway?]").condition(Condition.Context.PRIMITIVE)
174 def c4 = (Condition.KeyCondition) getParser("[!oneway?!]").condition(Condition.Context.PRIMITIVE)
175 def yes = getEnvironment("oneway", "yes")
176 def no = getEnvironment("oneway", "no")
177 def none = getEnvironment("no-oneway", "foo")
178 assert c1.applies(yes)
179 assert !c1.applies(no)
180 assert !c1.applies(none)
181 assert !c2.applies(yes)
182 assert c2.applies(no)
183 assert !c2.applies(none)
184 assert !c3.applies(yes)
185 assert c3.applies(no)
186 assert c3.applies(none)
187 assert c4.applies(yes)
188 assert !c4.applies(no)
189 assert c4.applies(none)
190 }
191
192 @Test
193 public void testRegexKeyCondition() throws Exception {
194 def c1 = (Condition.KeyCondition) getParser("[/.*:(backward|forward)\$/]").condition(Condition.Context.PRIMITIVE)
195 assert Condition.KeyMatchType.REGEX.equals(c1.matchType)
196 assert !c1.applies(getEnvironment("lanes", "3"))
197 assert c1.applies(getEnvironment("lanes:forward", "3"))
198 assert c1.applies(getEnvironment("lanes:backward", "3"))
199 assert !c1.applies(getEnvironment("lanes:foobar", "3"))
200 }
201
202 @Test
203 public void testNRegexKeyConditionSelector() throws Exception {
204 def s1 = getParser("*[sport][tourism != hotel]").selector()
205 assert s1.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar")))
206 assert !s1.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar tourism=hotel")))
207 def s2 = getParser("*[sport][tourism != hotel][leisure !~ /^(sports_centre|stadium|)\$/]").selector()
208 assert s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar")))
209 assert !s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar tourism=hotel")))
210 assert !s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar leisure=stadium")))
211 }
212
213 @Test
214 public void testKeyKeyCondition() throws Exception {
215 def c1 = (Condition.KeyValueCondition) getParser("[foo = *bar]").condition(Condition.Context.PRIMITIVE)
216 def w1 = new Way()
217 w1.put("foo", "123")
218 w1.put("bar", "456")
219 assert !c1.applies(new Environment(w1))
220 w1.put("bar", "123")
221 assert c1.applies(new Environment(w1))
222 def c2 = (Condition.KeyValueCondition) getParser("[foo =~ */bar/]").condition(Condition.Context.PRIMITIVE)
223 def w2 = new Way(w1)
224 w2.put("bar", "[0-9]{3}")
225 assert c2.applies(new Environment(w2))
226 w2.put("bar", "[0-9]")
227 assert c2.applies(new Environment(w2))
228 w2.put("bar", "^[0-9]\$")
229 assert !c2.applies(new Environment(w2))
230 }
231
232 @Test
233 public void testTicket8568() throws Exception {
234 def sheet = new MapCSSStyleSource("" +
235 "way { width: 5; }\n" +
236 "way[keyA], way[keyB] { width: eval(prop(width)+10); }")
237 sheet.loadStyleSource()
238 def mc = new MultiCascade()
239 sheet.apply(mc, OsmUtils.createPrimitive("way foo=bar"), 20, false)
240 assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 5
241 sheet.apply(mc, OsmUtils.createPrimitive("way keyA=true"), 20, false)
242 assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 15
243 sheet.apply(mc, OsmUtils.createPrimitive("way keyB=true"), 20, false)
244 assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 15
245 sheet.apply(mc, OsmUtils.createPrimitive("way keyA=true keyB=true"), 20, false)
246 assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 15
247 }
248
249 @Test
250 public void testTicket8071() throws Exception {
251 def sheet = new MapCSSStyleSource("" +
252 "*[rcn_ref], *[name] {text: concat(tag(rcn_ref), \" \", tag(name)); }")
253 sheet.loadStyleSource()
254 def mc = new MultiCascade()
255 sheet.apply(mc, OsmUtils.createPrimitive("way name=Foo"), 20, false)
256 assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == " Foo"
257 sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15"), 20, false)
258 assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == "15 "
259 sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15 name=Foo"), 20, false)
260 assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == "15 Foo"
261
262 sheet = new MapCSSStyleSource("" +
263 "*[rcn_ref], *[name] {text: join(\" - \", tag(rcn_ref), tag(ref), tag(name)); }")
264 sheet.loadStyleSource()
265 sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15 ref=1.5 name=Foo"), 20, false)
266 assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == "15 - 1.5 - Foo"
267 }
268
269 @Test
270 public void testColorNameTicket9191() throws Exception {
271 def e = new Environment(null, new MultiCascade(), Environment.DEFAULT_LAYER, null)
272 getParser("{color: testcolour1#88DD22}").declaration().instructions.get(0).execute(e)
273 def expected = new Color(0x88DD22)
274 assert e.getCascade(Environment.DEFAULT_LAYER).get("color") == expected
275 assert Main.pref.getDefaultColor("mappaint.mapcss.testcolour1") == expected
276 }
277
278 @Test
279 public void testColorNameTicket9191Alpha() throws Exception {
280 def e = new Environment(null, new MultiCascade(), Environment.DEFAULT_LAYER, null)
281 getParser("{color: testcolour2#12345678}").declaration().instructions.get(0).execute(e)
282 def expected = new Color(0x12, 0x34, 0x56, 0x78)
283 assert e.getCascade(Environment.DEFAULT_LAYER).get("color") == expected
284 assert Main.pref.getDefaultColor("mappaint.mapcss.testcolour2") == expected
285 }
286
287 @Test
288 public void testColorParsing() throws Exception {
289 assert ColorHelper.html2color("#12345678") == new Color(0x12, 0x34, 0x56, 0x78)
290 }
291
292 @Test
293 public void testChildSelectorGreaterThanSignIsOptional() throws Exception {
294 assert getParser("relation[type=route] way[highway]").child_selector().toString() ==
295 getParser("relation[type=route] > way[highway]").child_selector().toString()
296 }
297
298 @Test
299 public void testSiblingSelector() throws Exception {
300 def s1 = (Selector.ChildOrParentSelector) getParser("*[a?][parent_tag(\"highway\")=\"unclassified\"] + *[b?]").child_selector()
301 def ds = new DataSet()
302 def n1 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1, 2))
303 n1.put("a", "true")
304 def n2 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1.1, 2.2))
305 n2.put("b", "true")
306 def w = new Way()
307 w.put("highway", "unclassified")
308 ds.addPrimitive(n1)
309 ds.addPrimitive(n2)
310 ds.addPrimitive(w)
311 w.addNode(n1)
312 w.addNode(n2)
313
314 def e = new Environment(n2)
315 assert s1.matches(e)
316 assert e.osm == n2
317 assert e.child == n1
318 assert e.parent == w
319 assert !s1.matches(new Environment(n1))
320 assert !s1.matches(new Environment(w))
321 }
322
323 @Test
324 public void testSiblingSelectorInterpolation() throws Exception {
325 def s1 = (Selector.ChildOrParentSelector) getParser(
326 "*[tag(\"addr:housenumber\") > child_tag(\"addr:housenumber\")][regexp_test(\"even|odd\", parent_tag(\"addr:interpolation\"))]" +
327 " + *[addr:housenumber]").child_selector()
328 def ds = new DataSet()
329 def n1 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1, 2))
330 n1.put("addr:housenumber", "10")
331 def n2 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1.1, 2.2))
332 n2.put("addr:housenumber", "100")
333 def n3 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1.2, 2.3))
334 n3.put("addr:housenumber", "20")
335 def w = new Way()
336 w.put("addr:interpolation", "even")
337 ds.addPrimitive(n1)
338 ds.addPrimitive(n2)
339 ds.addPrimitive(n3)
340 ds.addPrimitive(w)
341 w.addNode(n1)
342 w.addNode(n2)
343 w.addNode(n3)
344
345 assert s1.right.matches(new Environment(n3))
346 assert s1.left.matches(new Environment(n2).withChild(n3).withParent(w))
347 assert s1.matches(new Environment(n3))
348 assert !s1.matches(new Environment(n1))
349 assert !s1.matches(new Environment(n2))
350 assert !s1.matches(new Environment(w))
351 }
352
353 @Test
354 public void testInvalidBaseSelector() throws Exception {
355 def css = new MapCSSStyleSource("invalid_base[key=value] {}")
356 css.loadStyleSource()
357 assert !css.getErrors().isEmpty()
358 assert css.getErrors().iterator().next().toString().contains("Unknown MapCSS base selector invalid_base")
359 }
360
361 @Test
362 public void testMinMaxFunctions() throws Exception {
363 def sheet = new MapCSSStyleSource("* {" +
364 "min_value: min(tag(x), tag(y), tag(z)); " +
365 "max_value: max(tag(x), tag(y), tag(z)); " +
366 "max_split: max(split(\";\", tag(widths))); " +
367 "}")
368 sheet.loadStyleSource()
369 def mc = new MultiCascade()
370
371 sheet.apply(mc, OsmUtils.createPrimitive("way x=4 y=6 z=8 u=100"), 20, false)
372 assert mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", Float.NaN, Float.class) == 4.0f
373 assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", Float.NaN, Float.class) == 8.0f
374
375 sheet.apply(mc, OsmUtils.createPrimitive("way x=4 y=6 widths=1;2;8;56;3;a"), 20, false)
376 assert mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", -777f, Float.class) == 4
377 assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", -777f, Float.class) == 6
378 assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_split", -777f, Float.class) == 56
379 }
380}
Note: See TracBrowser for help on using the repository browser.