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

Last change on this file since 7166 was 7166, checked in by simon04, 10 years ago

fix #10059 - MapCSS, child selector: make greater-than-sign optional

The following selectors are equivalent:
relation[type=route] way[highway]
relation[type=route] > way[highway]

File size: 16.4 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.TestUtils
10import org.openstreetmap.josm.data.coor.LatLon
11import org.openstreetmap.josm.data.osm.DataSet
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(TestUtils.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, TestUtils.createPrimitive("way highway=path"), 1, null, 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, TestUtils.createPrimitive("way highway=residential"), 1, null, 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, TestUtils.createPrimitive("way highway=footway"), 1, null, 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 testStandardKeyCondition() throws Exception {
125 def c1 = (Condition.KeyCondition) getParser("[ highway ]").condition(Condition.Context.PRIMITIVE)
126 assert c1.matchType == null
127 assert c1.applies(getEnvironment("highway", "unclassified"))
128 assert !c1.applies(getEnvironment("railway", "rail"))
129 def c2 = (Condition.KeyCondition) getParser("[\"/slash/\"]").condition(Condition.Context.PRIMITIVE)
130 assert c2.matchType == null
131 assert c2.applies(getEnvironment("/slash/", "yes"))
132 assert !c2.applies(getEnvironment("\"slash\"", "no"))
133 }
134
135 @Test
136 public void testYesNoKeyCondition() throws Exception {
137 def c1 = (Condition.KeyCondition) getParser("[oneway?]").condition(Condition.Context.PRIMITIVE)
138 def c2 = (Condition.KeyCondition) getParser("[oneway?!]").condition(Condition.Context.PRIMITIVE)
139 def c3 = (Condition.KeyCondition) getParser("[!oneway?]").condition(Condition.Context.PRIMITIVE)
140 def c4 = (Condition.KeyCondition) getParser("[!oneway?!]").condition(Condition.Context.PRIMITIVE)
141 def yes = getEnvironment("oneway", "yes")
142 def no = getEnvironment("oneway", "no")
143 def none = getEnvironment("no-oneway", "foo")
144 assert c1.applies(yes)
145 assert !c1.applies(no)
146 assert !c1.applies(none)
147 assert !c2.applies(yes)
148 assert c2.applies(no)
149 assert !c2.applies(none)
150 assert !c3.applies(yes)
151 assert c3.applies(no)
152 assert c3.applies(none)
153 assert c4.applies(yes)
154 assert !c4.applies(no)
155 assert c4.applies(none)
156 }
157
158 @Test
159 public void testRegexKeyCondition() throws Exception {
160 def c1 = (Condition.KeyCondition) getParser("[/.*:(backward|forward)\$/]").condition(Condition.Context.PRIMITIVE)
161 assert Condition.KeyMatchType.REGEX.equals(c1.matchType)
162 assert !c1.applies(getEnvironment("lanes", "3"))
163 assert c1.applies(getEnvironment("lanes:forward", "3"))
164 assert c1.applies(getEnvironment("lanes:backward", "3"))
165 assert !c1.applies(getEnvironment("lanes:foobar", "3"))
166 }
167
168 @Test
169 public void testNRegexKeyConditionSelector() throws Exception {
170 def s1 = getParser("*[sport][tourism != hotel]").selector()
171 assert s1.matches(new Environment().withPrimitive(TestUtils.createPrimitive("node sport=foobar")))
172 assert !s1.matches(new Environment().withPrimitive(TestUtils.createPrimitive("node sport=foobar tourism=hotel")))
173 def s2 = getParser("*[sport][tourism != hotel][leisure !~ /^(sports_centre|stadium|)\$/]").selector()
174 assert s2.matches(new Environment().withPrimitive(TestUtils.createPrimitive("node sport=foobar")))
175 assert !s2.matches(new Environment().withPrimitive(TestUtils.createPrimitive("node sport=foobar tourism=hotel")))
176 assert !s2.matches(new Environment().withPrimitive(TestUtils.createPrimitive("node sport=foobar leisure=stadium")))
177 }
178
179 @Test
180 public void testKeyKeyCondition() throws Exception {
181 def c1 = (Condition.KeyValueCondition) getParser("[foo = *bar]").condition(Condition.Context.PRIMITIVE)
182 def w1 = new Way()
183 w1.put("foo", "123")
184 w1.put("bar", "456")
185 assert !c1.applies(new Environment().withPrimitive(w1))
186 w1.put("bar", "123")
187 assert c1.applies(new Environment().withPrimitive(w1))
188 def c2 = (Condition.KeyValueCondition) getParser("[foo =~ */bar/]").condition(Condition.Context.PRIMITIVE)
189 def w2 = new Way(w1)
190 w2.put("bar", "[0-9]{3}")
191 assert c2.applies(new Environment().withPrimitive(w2))
192 w2.put("bar", "[0-9]")
193 assert c2.applies(new Environment().withPrimitive(w2))
194 w2.put("bar", "^[0-9]\$")
195 assert !c2.applies(new Environment().withPrimitive(w2))
196 }
197
198 @Test
199 public void testTicket8568() throws Exception {
200 def sheet = new MapCSSStyleSource("" +
201 "way { width: 5; }\n" +
202 "way[keyA], way[keyB] { width: eval(prop(width)+10); }")
203 sheet.loadStyleSource()
204 def mc = new MultiCascade()
205 sheet.apply(mc, TestUtils.createPrimitive("way foo=bar"), 20, null, false)
206 assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 5
207 sheet.apply(mc, TestUtils.createPrimitive("way keyA=true"), 20, null, false)
208 assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 15
209 sheet.apply(mc, TestUtils.createPrimitive("way keyB=true"), 20, null, false)
210 assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 15
211 sheet.apply(mc, TestUtils.createPrimitive("way keyA=true keyB=true"), 20, null, false)
212 assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 15
213 }
214
215 @Test
216 public void testTicket8071() throws Exception {
217 def sheet = new MapCSSStyleSource("" +
218 "*[rcn_ref], *[name] {text: concat(tag(rcn_ref), \" \", tag(name)); }")
219 sheet.loadStyleSource()
220 def mc = new MultiCascade()
221 sheet.apply(mc, TestUtils.createPrimitive("way name=Foo"), 20, null, false)
222 assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == " Foo"
223 sheet.apply(mc, TestUtils.createPrimitive("way rcn_ref=15"), 20, null, false)
224 assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == "15 "
225 sheet.apply(mc, TestUtils.createPrimitive("way rcn_ref=15 name=Foo"), 20, null, false)
226 assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == "15 Foo"
227
228 sheet = new MapCSSStyleSource("" +
229 "*[rcn_ref], *[name] {text: join(\" - \", tag(rcn_ref), tag(ref), tag(name)); }")
230 sheet.loadStyleSource()
231 sheet.apply(mc, TestUtils.createPrimitive("way rcn_ref=15 ref=1.5 name=Foo"), 20, null, false)
232 assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == "15 - 1.5 - Foo"
233 }
234
235 @Test
236 public void testColorNameTicket9191() throws Exception {
237 def e = new Environment(null, new MultiCascade(), Environment.DEFAULT_LAYER, null)
238 getParser("{color: testcolour1#88DD22}").declaration().instructions.get(0).execute(e)
239 def expected = new Color(0x88DD22)
240 assert e.getCascade(Environment.DEFAULT_LAYER).get("color") == expected
241 assert Main.pref.getDefaultColor("mappaint.mapcss.testcolour1") == expected
242 }
243
244 @Test
245 public void testColorNameTicket9191Alpha() throws Exception {
246 def e = new Environment(null, new MultiCascade(), Environment.DEFAULT_LAYER, null)
247 getParser("{color: testcolour2#12345678}").declaration().instructions.get(0).execute(e)
248 def expected = new Color(0x12, 0x34, 0x56, 0x78)
249 assert e.getCascade(Environment.DEFAULT_LAYER).get("color") == expected
250 assert Main.pref.getDefaultColor("mappaint.mapcss.testcolour2") == expected
251 }
252
253 @Test
254 public void testColorParsing() throws Exception {
255 assert ColorHelper.html2color("#12345678") == new Color(0x12, 0x34, 0x56, 0x78)
256 }
257
258 @Test
259 public void testChildSelectorGreaterThanSignIsOptional() throws Exception {
260 assert getParser("relation[type=route] way[highway]").child_selector().toString() ==
261 getParser("relation[type=route] > way[highway]").child_selector().toString()
262 }
263
264 @Test
265 public void testSiblingSelector() throws Exception {
266 def s1 = (Selector.ChildOrParentSelector) getParser("*[a?][parent_tag(\"highway\")=\"unclassified\"] + *[b?]").child_selector()
267 def ds = new DataSet()
268 def n1 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1, 2))
269 n1.put("a", "true")
270 def n2 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1.1, 2.2))
271 n2.put("b", "true")
272 def w = new Way()
273 w.put("highway", "unclassified")
274 ds.addPrimitive(n1)
275 ds.addPrimitive(n2)
276 ds.addPrimitive(w)
277 w.addNode(n1)
278 w.addNode(n2)
279
280 def e = new Environment().withPrimitive(n2)
281 assert s1.matches(e)
282 assert e.osm == n2
283 assert e.child == n1
284 assert e.parent == w
285 assert !s1.matches(new Environment().withPrimitive(n1))
286 assert !s1.matches(new Environment().withPrimitive(w))
287 }
288
289 @Test
290 public void testSiblingSelectorInterpolation() throws Exception {
291 def s1 = (Selector.ChildOrParentSelector) getParser(
292 "*[tag(\"addr:housenumber\") > child_tag(\"addr:housenumber\")][regexp_test(\"even|odd\", parent_tag(\"addr:interpolation\"))]" +
293 " + *[addr:housenumber]").child_selector()
294 def ds = new DataSet()
295 def n1 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1, 2))
296 n1.put("addr:housenumber", "10")
297 def n2 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1.1, 2.2))
298 n2.put("addr:housenumber", "100")
299 def n3 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1.2, 2.3))
300 n3.put("addr:housenumber", "20")
301 def w = new Way()
302 w.put("addr:interpolation", "even")
303 ds.addPrimitive(n1)
304 ds.addPrimitive(n2)
305 ds.addPrimitive(n3)
306 ds.addPrimitive(w)
307 w.addNode(n1)
308 w.addNode(n2)
309 w.addNode(n3)
310
311 assert s1.right.matches(new Environment().withPrimitive(n3))
312 assert s1.left.matches(new Environment().withPrimitive(n2).withChild(n3).withParent(w))
313 assert s1.matches(new Environment().withPrimitive(n3))
314 assert !s1.matches(new Environment().withPrimitive(n1))
315 assert !s1.matches(new Environment().withPrimitive(n2))
316 assert !s1.matches(new Environment().withPrimitive(w))
317 }
318
319 @Test
320 public void testInvalidBaseSelector() throws Exception {
321 def css = new MapCSSStyleSource("invalid_base[key=value] {}")
322 css.loadStyleSource()
323 assert !css.getErrors().isEmpty()
324 assert css.getErrors().iterator().next().toString().contains("Unknown MapCSS base selector invalid_base")
325 }
326
327 @Test
328 public void testMinMaxFunctions() throws Exception {
329 def sheet = new MapCSSStyleSource("* {" +
330 "min_value: min(tag(x), tag(y), tag(z)); " +
331 "max_value: max(tag(x), tag(y), tag(z)); " +
332 "}")
333 sheet.loadStyleSource()
334 def mc = new MultiCascade()
335
336 sheet.apply(mc, TestUtils.createPrimitive("way x=4 y=6 z=8 u=100"), 20, null, false)
337 assert mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", Float.NaN, Float.class) == 4.0f
338 assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", Float.NaN, Float.class) == 8.0f
339
340 sheet.apply(mc, TestUtils.createPrimitive("way x=4 y=6"), 20, null, false)
341 assert mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", -777f, Float.class) == -777f
342 assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", -777f, Float.class) == -777f
343 }
344}
Note: See TracBrowser for help on using the repository browser.