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

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

see #11278 - Add test case w.r.t. parent_tag

This checks whether the child's tag equals the parent's tag.

  • Property svn:eol-style set to native
File size: 20.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.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.Node
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("http://kothic.googlecode.com/hg/src/styles/default.mapcss").openStream(), "UTF-8")
37 new MapCSSParser(new URL("http://kothic.googlecode.com/hg/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}
Note: See TracBrowser for help on using the repository browser.