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

Last change on this file since 10193 was 10193, checked in by Don-vip, 4 years ago

kothic google code website has been archived ==> use new Github repository

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