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

Last change on this file since 12990 was 12990, checked in by bastiK, 7 years ago

see #15410 - update tests + minor fixes (2)

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