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

Last change on this file since 7938 was 7938, checked in by bastiK, 5 years ago

add more subversion property svn:eol=native

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