source: josm/trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.java@ 17531

Last change on this file since 17531 was 17275, checked in by Don-vip, 3 years ago

see #16567 - upgrade almost all tests to JUnit 5, except those depending on WiremockRule

See https://github.com/tomakehurst/wiremock/issues/684

  • Property svn:eol-style set to native
File size: 31.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint.mapcss;
3
4import static org.junit.jupiter.api.Assertions.assertEquals;
5import static org.junit.jupiter.api.Assertions.assertFalse;
6import static org.junit.jupiter.api.Assertions.assertNotNull;
7import static org.junit.jupiter.api.Assertions.assertNull;
8import static org.junit.jupiter.api.Assertions.assertThrows;
9import static org.junit.jupiter.api.Assertions.assertTrue;
10import static org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context.PRIMITIVE;
11
12import java.awt.Color;
13import java.io.StringReader;
14import java.util.Arrays;
15import java.util.List;
16
17import org.junit.Assert;
18import org.junit.jupiter.api.Test;
19import org.junit.jupiter.api.extension.RegisterExtension;
20import org.openstreetmap.josm.TestUtils;
21import org.openstreetmap.josm.data.coor.LatLon;
22import org.openstreetmap.josm.data.osm.DataSet;
23import org.openstreetmap.josm.data.osm.Node;
24import org.openstreetmap.josm.data.osm.OsmUtils;
25import org.openstreetmap.josm.data.osm.Relation;
26import org.openstreetmap.josm.data.osm.RelationMember;
27import org.openstreetmap.josm.data.osm.Way;
28import org.openstreetmap.josm.gui.mappaint.Environment;
29import org.openstreetmap.josm.gui.mappaint.MultiCascade;
30import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.ClassCondition;
31import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyCondition;
32import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyMatchType;
33import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyValueCondition;
34import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.Op;
35import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.PseudoClassCondition;
36import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.RegexpKeyValueRegexpCondition;
37import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.SimpleKeyValueCondition;
38import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
39import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
40import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException;
41import org.openstreetmap.josm.testutils.JOSMTestRules;
42import org.openstreetmap.josm.tools.ColorHelper;
43
44import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
45
46/**
47 * Unit tests of {@link MapCSSParser}.
48 */
49class MapCSSParserTest {
50
51 protected static Environment getEnvironment(String key, String value) {
52 return new Environment(OsmUtils.createPrimitive("way " + key + "=" + value));
53 }
54
55 protected static MapCSSParser getParser(String stringToParse) {
56 return new MapCSSParser(new StringReader(stringToParse));
57 }
58
59 /**
60 * Setup rule
61 */
62 @RegisterExtension
63 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
64 public JOSMTestRules test = new JOSMTestRules().projection();
65
66 @Test
67 void testDeclarations() throws Exception {
68 getParser("{ opacity: 0.5; color: rgb(1.0, 0.0, 0.0); }").declaration();
69 getParser("{ set tag=value; }").declaration(); //set a tag
70 getParser("{ set tag; }").declaration(); // set a tag to 'yes'
71 getParser("{ opacity: eval(\"tag('population')/100000\"); }").declaration();
72 getParser("{ set width_in_metres=eval(\"tag('lanes')*3\"); }").declaration();
73 }
74
75 @Test
76 void testClassCondition() throws Exception {
77 List<Condition> conditions = ((Selector.GeneralSelector) getParser("way[name=X].highway:closed").selector()).conds;
78 assertTrue(conditions.get(0) instanceof SimpleKeyValueCondition);
79 assertTrue(conditions.get(0).applies(getEnvironment("name", "X")));
80 assertTrue(conditions.get(1) instanceof ClassCondition);
81 assertTrue(conditions.get(2) instanceof PseudoClassCondition);
82 assertFalse(conditions.get(2).applies(getEnvironment("name", "X")));
83 }
84
85 @Test
86 void testPseudoClassCondition() throws Exception {
87 Condition c1 = ((Selector.GeneralSelector) getParser("way!:area-style").selector()).conds.get(0);
88 Condition c2 = ((Selector.GeneralSelector) getParser("way!:areaStyle").selector()).conds.get(0);
89 Condition c3 = ((Selector.GeneralSelector) getParser("way!:area_style").selector()).conds.get(0);
90 assertEquals("!:areaStyle", c1.toString());
91 assertEquals("!:areaStyle", c2.toString());
92 assertEquals("!:areaStyle", c3.toString());
93 }
94
95 @Test
96 void testClassMatching() throws Exception {
97 MapCSSStyleSource css = new MapCSSStyleSource(
98 "way[highway=footway] { set .path; color: #FF6644; width: 2; }\n" +
99 "way[highway=path] { set path; color: brown; width: 2; }\n" +
100 "way[\"set\"=escape] { }\n" +
101 "way.path { text:auto; text-color: green; text-position: line; text-offset: 5; }\n" +
102 "way!.path { color: orange; }\n"
103 );
104 css.loadStyleSource();
105 assertTrue(css.getErrors().isEmpty());
106 MultiCascade mc1 = new MultiCascade();
107 css.apply(mc1, OsmUtils.createPrimitive("way highway=path"), 1, false);
108 assertEquals("green", mc1.getCascade("default").get("text-color", null, String.class));
109 assertEquals("brown", mc1.getCascade("default").get("color", null, String.class));
110 MultiCascade mc2 = new MultiCascade();
111 css.apply(mc2, OsmUtils.createPrimitive("way highway=residential"), 1, false);
112 assertEquals("orange", mc2.getCascade("default").get("color", null, String.class));
113 assertNull(mc2.getCascade("default").get("text-color", null, String.class));
114 MultiCascade mc3 = new MultiCascade();
115 css.apply(mc3, OsmUtils.createPrimitive("way highway=footway"), 1, false);
116 assertEquals(ColorHelper.html2color("#FF6644"), mc3.getCascade("default").get("color", null, Color.class));
117 }
118
119 @Test
120 void testEqualCondition() throws Exception {
121 Condition condition = getParser("[surface=paved]").condition(PRIMITIVE);
122 assertTrue(condition instanceof SimpleKeyValueCondition);
123 assertEquals("surface", ((SimpleKeyValueCondition) condition).k);
124 assertEquals("paved", ((SimpleKeyValueCondition) condition).v);
125 assertTrue(condition.applies(getEnvironment("surface", "paved")));
126 assertFalse(condition.applies(getEnvironment("surface", "unpaved")));
127 }
128
129 @Test
130 void testNotEqualCondition() throws Exception {
131 KeyValueCondition condition = (KeyValueCondition) getParser("[surface!=paved]").condition(PRIMITIVE);
132 assertEquals(Op.NEQ, condition.op);
133 assertFalse(condition.applies(getEnvironment("surface", "paved")));
134 assertTrue(condition.applies(getEnvironment("surface", "unpaved")));
135 }
136
137 @Test
138 void testRegexCondition() throws Exception {
139 KeyValueCondition condition = (KeyValueCondition) getParser("[surface=~/paved|unpaved/]").condition(PRIMITIVE);
140 assertEquals(Op.REGEX, condition.op);
141 assertTrue(condition.applies(getEnvironment("surface", "unpaved")));
142 assertFalse(condition.applies(getEnvironment("surface", "grass")));
143 }
144
145 @Test
146 void testRegexConditionParenthesis() throws Exception {
147 KeyValueCondition condition = (KeyValueCondition) getParser("[name =~ /^\\(foo\\)/]").condition(PRIMITIVE);
148 assertTrue(condition.applies(getEnvironment("name", "(foo)")));
149 assertFalse(condition.applies(getEnvironment("name", "foo")));
150 assertFalse(condition.applies(getEnvironment("name", "((foo))")));
151 }
152
153 @Test
154 void testNegatedRegexCondition() throws Exception {
155 KeyValueCondition condition = (KeyValueCondition) getParser("[surface!~/paved|unpaved/]").condition(PRIMITIVE);
156 assertEquals(Op.NREGEX, condition.op);
157 assertFalse(condition.applies(getEnvironment("surface", "unpaved")));
158 assertTrue(condition.applies(getEnvironment("surface", "grass")));
159 }
160
161 @Test
162 void testBeginsEndsWithCondition() throws Exception {
163 KeyValueCondition condition = (KeyValueCondition) getParser("[foo ^= bar]").condition(PRIMITIVE);
164 assertEquals(Op.BEGINS_WITH, condition.op);
165 assertTrue(condition.applies(getEnvironment("foo", "bar123")));
166 assertFalse(condition.applies(getEnvironment("foo", "123bar")));
167 assertFalse(condition.applies(getEnvironment("foo", "123bar123")));
168 condition = (KeyValueCondition) getParser("[foo $= bar]").condition(PRIMITIVE);
169 assertEquals(Op.ENDS_WITH, condition.op);
170 assertFalse(condition.applies(getEnvironment("foo", "bar123")));
171 assertTrue(condition.applies(getEnvironment("foo", "123bar")));
172 assertFalse(condition.applies(getEnvironment("foo", "123bar123")));
173 }
174
175 @Test
176 void testOneOfCondition() throws Exception {
177 Condition condition = getParser("[vending~=stamps]").condition(PRIMITIVE);
178 assertTrue(condition.applies(getEnvironment("vending", "stamps")));
179 assertTrue(condition.applies(getEnvironment("vending", "bar;stamps;foo")));
180 assertFalse(condition.applies(getEnvironment("vending", "every;thing;else")));
181 assertFalse(condition.applies(getEnvironment("vending", "or_nothing")));
182 }
183
184 @Test
185 void testStandardKeyCondition() throws Exception {
186 KeyCondition c1 = (KeyCondition) getParser("[ highway ]").condition(PRIMITIVE);
187 assertEquals(KeyMatchType.EQ, c1.matchType);
188 assertTrue(c1.applies(getEnvironment("highway", "unclassified")));
189 assertFalse(c1.applies(getEnvironment("railway", "rail")));
190 KeyCondition c2 = (KeyCondition) getParser("[\"/slash/\"]").condition(PRIMITIVE);
191 assertEquals(KeyMatchType.EQ, c2.matchType);
192 assertTrue(c2.applies(getEnvironment("/slash/", "yes")));
193 assertFalse(c2.applies(getEnvironment("\"slash\"", "no")));
194 }
195
196 @Test
197 void testYesNoKeyCondition() throws Exception {
198 KeyCondition c1 = (KeyCondition) getParser("[oneway?]").condition(PRIMITIVE);
199 KeyCondition c2 = (KeyCondition) getParser("[oneway?!]").condition(PRIMITIVE);
200 KeyCondition c3 = (KeyCondition) getParser("[!oneway?]").condition(PRIMITIVE);
201 KeyCondition c4 = (KeyCondition) getParser("[!oneway?!]").condition(PRIMITIVE);
202 Environment yes = getEnvironment("oneway", "yes");
203 Environment no = getEnvironment("oneway", "no");
204 Environment none = getEnvironment("no-oneway", "foo");
205 assertTrue(c1.applies(yes));
206 assertFalse(c1.applies(no));
207 assertFalse(c1.applies(none));
208 assertFalse(c2.applies(yes));
209 assertTrue(c2.applies(no));
210 assertFalse(c2.applies(none));
211 assertFalse(c3.applies(yes));
212 assertTrue(c3.applies(no));
213 assertTrue(c3.applies(none));
214 assertTrue(c4.applies(yes));
215 assertFalse(c4.applies(no));
216 assertTrue(c4.applies(none));
217 }
218
219 @Test
220 void testRegexKeyCondition() throws Exception {
221 KeyCondition c1 = (KeyCondition) getParser("[/.*:(backward|forward)$/]").condition(PRIMITIVE);
222 assertEquals(KeyMatchType.REGEX, c1.matchType);
223 assertFalse(c1.applies(getEnvironment("lanes", "3")));
224 assertTrue(c1.applies(getEnvironment("lanes:forward", "3")));
225 assertTrue(c1.applies(getEnvironment("lanes:backward", "3")));
226 assertFalse(c1.applies(getEnvironment("lanes:foobar", "3")));
227 }
228
229 @Test
230 void testRegexKeyValueRegexpCondition() throws Exception {
231 RegexpKeyValueRegexpCondition c1 = (RegexpKeyValueRegexpCondition) getParser("[/^name/=~/Test/]").condition(PRIMITIVE);
232 assertEquals("^name", c1.keyPattern.pattern());
233 assertEquals("Test", c1.pattern.pattern());
234 assertTrue(c1.applies(getEnvironment("name", "Test St")));
235 assertFalse(c1.applies(getEnvironment("alt_name", "Test St")));
236 }
237
238 @Test
239 void testNRegexKeyConditionSelector() throws Exception {
240 Selector s1 = getParser("*[sport][tourism != hotel]").selector();
241 assertTrue(s1.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar"))));
242 assertFalse(s1.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar tourism=hotel"))));
243 Selector s2 = getParser("*[sport][tourism != hotel][leisure !~ /^(sports_centre|stadium|)$/]").selector();
244 assertTrue(s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar"))));
245 assertFalse(s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar tourism=hotel"))));
246 assertFalse(s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar leisure=stadium"))));
247 }
248
249 @Test
250 void testKeyKeyCondition() throws Exception {
251 KeyValueCondition c1 = (KeyValueCondition) getParser("[foo = *bar]").condition(PRIMITIVE);
252 Way w1 = new Way();
253 w1.put("foo", "123");
254 w1.put("bar", "456");
255 assertFalse(c1.applies(new Environment(w1)));
256 w1.put("bar", "123");
257 assertTrue(c1.applies(new Environment(w1)));
258 KeyValueCondition c2 = (KeyValueCondition) getParser("[foo =~ */bar/]").condition(PRIMITIVE);
259 Way w2 = new Way(w1);
260 w2.put("bar", "[0-9]{3}");
261 assertTrue(c2.applies(new Environment(w2)));
262 w2.put("bar", "[0-9]");
263 assertTrue(c2.applies(new Environment(w2)));
264 w2.put("bar", "^[0-9]$");
265 assertFalse(c2.applies(new Environment(w2)));
266 }
267
268 /**
269 * Make certain that getting tags by regex works
270 * @throws Exception if there is an assert error (or another error)
271 */
272 @Test
273 void testTagRegex() throws Exception {
274 DataSet ds = new DataSet();
275 Way way1 = TestUtils.newWay("old_ref=A1 ref=A2", new Node(new LatLon(1, 1)), new Node(new LatLon(2, 2)));
276 for (Node node : way1.getNodes()) {
277 ds.addPrimitive(node);
278 }
279 ds.addPrimitive(way1);
280
281 tagRegex(way1, "way[ref][count(tag_regex(\"ref\")) > 1] {}", new Boolean[] {true, false, false, true, false});
282 way1.keySet().forEach(key -> way1.put(key, null));
283 way1.put("old_ref", "A1");
284 way1.put("ref", "A2");
285 tagRegex(way1, "way[ref][count(tag_regex(\"ref\", \"i\")) > 1] {}", new Boolean[] {true, false, false, true, true});
286 }
287
288 private void tagRegex(Way way, String parserString, Boolean[] expected) throws Exception {
289 Selector selector = getParser(parserString).selector();
290 Assert.assertEquals(expected[0], selector.matches(new Environment(way)));
291 way.put("old_ref", null);
292 Assert.assertEquals(expected[1], selector.matches(new Environment(way)));
293 way.put("no_match_tag", "false");
294 Assert.assertEquals(expected[2], selector.matches(new Environment(way)));
295 way.put("old_ref", "A22");
296 Assert.assertEquals(expected[3], selector.matches(new Environment(way)));
297 way.put("old_ref", null);
298 way.put("OLD_REF", "A23");
299 Assert.assertEquals(expected[4], selector.matches(new Environment(way)));
300 }
301
302 @Test
303 void testParentTag() throws Exception {
304 Selector c1 = getParser("way[foo] > node[tag(\"foo\")=parent_tag(\"foo\")] {}").child_selector();
305 DataSet ds = new DataSet();
306 Way w1 = new Way();
307 Way w2 = new Way();
308 Node n1 = new Node(new LatLon(1, 1));
309 Node n2 = new Node(new LatLon(2, 2));
310 w1.put("foo", "123");
311 w2.put("foo", "123");
312 n1.put("foo", "123");
313 n2.put("foo", "0");
314 ds.addPrimitive(w1);
315 ds.addPrimitive(n1);
316 ds.addPrimitive(n2);
317 w1.addNode(n1);
318 w2.addNode(n2);
319 assertTrue(c1.matches(new Environment(n1)));
320 assertFalse(c1.matches(new Environment(n2)));
321 assertFalse(c1.matches(new Environment(w1)));
322 assertFalse(c1.matches(new Environment(w2)));
323 n1.put("foo", "0");
324 assertFalse(c1.matches(new Environment(n1)));
325 n1.put("foo", "123");
326 assertTrue(c1.matches(new Environment(n1)));
327 }
328
329 /**
330 * Test case for {@link Functions#trim_list}
331 */
332 @Test
333 void testTrimList() {
334 List<String> trimmed = Functions.trim_list(Arrays.asList(" A1 ", "A2", " A3", "A4 ", ""));
335 assertEquals(4, trimmed.size());
336 assertEquals("A1", trimmed.get(0));
337 assertEquals("A2", trimmed.get(1));
338 assertEquals("A3", trimmed.get(2));
339 assertEquals("A4", trimmed.get(3));
340 }
341
342 @Test
343 void testTicket8568() throws Exception {
344 MapCSSStyleSource sheet = new MapCSSStyleSource(
345 "way { width: 5; }\n" +
346 "way[keyA], way[keyB] { width: eval(prop(width)+10); }");
347 sheet.loadStyleSource();
348 MultiCascade mc = new MultiCascade();
349 sheet.apply(mc, OsmUtils.createPrimitive("way foo=bar"), 20, false);
350 assertEquals(Float.valueOf(5f), mc.getCascade(Environment.DEFAULT_LAYER).get("width"));
351 sheet.apply(mc, OsmUtils.createPrimitive("way keyA=true"), 20, false);
352 assertEquals(Float.valueOf(15f), mc.getCascade(Environment.DEFAULT_LAYER).get("width"));
353 sheet.apply(mc, OsmUtils.createPrimitive("way keyB=true"), 20, false);
354 assertEquals(Float.valueOf(15f), mc.getCascade(Environment.DEFAULT_LAYER).get("width"));
355 sheet.apply(mc, OsmUtils.createPrimitive("way keyA=true keyB=true"), 20, false);
356 assertEquals(Float.valueOf(15f), mc.getCascade(Environment.DEFAULT_LAYER).get("width"));
357 }
358
359 @Test
360 void testTicket8071() throws Exception {
361 MapCSSStyleSource sheet = new MapCSSStyleSource(
362 "*[rcn_ref], *[name] {text: concat(tag(rcn_ref), \" \", tag(name)); }");
363 sheet.loadStyleSource();
364 MultiCascade mc = new MultiCascade();
365 sheet.apply(mc, OsmUtils.createPrimitive("way name=Foo"), 20, false);
366 assertEquals(" Foo", mc.getCascade(Environment.DEFAULT_LAYER).get("text"));
367 sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15"), 20, false);
368 assertEquals("15 ", mc.getCascade(Environment.DEFAULT_LAYER).get("text"));
369 sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15 name=Foo"), 20, false);
370 assertEquals("15 Foo", mc.getCascade(Environment.DEFAULT_LAYER).get("text"));
371
372 sheet = new MapCSSStyleSource("" +
373 "*[rcn_ref], *[name] {text: join(\" - \", tag(rcn_ref), tag(ref), tag(name)); }");
374 sheet.loadStyleSource();
375 sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15 ref=1.5 name=Foo"), 20, false);
376 assertEquals("15 - 1.5 - Foo", mc.getCascade(Environment.DEFAULT_LAYER).get("text"));
377 }
378
379 @Test
380 void testColorNameTicket9191() throws Exception {
381 Environment e = new Environment(null, new MultiCascade(), Environment.DEFAULT_LAYER, null);
382 getParser("{color: testcolour1#88DD22}").declaration().instructions.get(0).execute(e);
383 Color expected = new Color(0x88DD22);
384 assertEquals(expected, e.getCascade(Environment.DEFAULT_LAYER).get("color"));
385 }
386
387 @Test
388 void testColorNameTicket9191Alpha() throws Exception {
389 Environment e = new Environment(null, new MultiCascade(), Environment.DEFAULT_LAYER, null);
390 getParser("{color: testcolour2#12345678}").declaration().instructions.get(0).execute(e);
391 Color expected = new Color(0x12, 0x34, 0x56, 0x78);
392 assertEquals(expected, e.getCascade(Environment.DEFAULT_LAYER).get("color"));
393 }
394
395 @Test
396 void testColorParsing() throws Exception {
397 assertEquals(new Color(0x12, 0x34, 0x56, 0x78), ColorHelper.html2color("#12345678"));
398 }
399
400 @Test
401 void testChildSelectorGreaterThanSignIsOptional() throws Exception {
402 assertEquals(
403 getParser("relation[type=route] way[highway]").child_selector().toString(),
404 getParser("relation[type=route] > way[highway]").child_selector().toString());
405 }
406
407 @Test
408 void testSiblingSelector() throws Exception {
409 ChildOrParentSelector s1 = (Selector.ChildOrParentSelector) getParser(
410 "*[a?][parent_tag(\"highway\")=\"unclassified\"] + *[b?]").child_selector();
411 DataSet ds = new DataSet();
412 Node n1 = new Node(new LatLon(1, 2));
413 n1.put("a", "true");
414 Node n2 = new Node(new LatLon(1.1, 2.2));
415 n2.put("b", "true");
416 Way w = new Way();
417 w.put("highway", "unclassified");
418 ds.addPrimitive(n1);
419 ds.addPrimitive(n2);
420 ds.addPrimitive(w);
421 w.addNode(n1);
422 w.addNode(n2);
423
424 Environment e = new Environment(n2);
425 assertTrue(s1.matches(e));
426 assertEquals(n2, e.osm);
427 assertEquals(n1, e.child);
428 assertEquals(w, e.parent);
429 assertFalse(s1.matches(new Environment(n1)));
430 assertFalse(s1.matches(new Environment(w)));
431 }
432
433 @Test
434 void testParentTags() throws Exception {
435 DataSet ds = new DataSet();
436 Node n = new Node(new LatLon(1, 2));
437 n.put("foo", "bar");
438 Way w1 = new Way();
439 w1.put("ref", "x10");
440 Way w2 = new Way();
441 w2.put("ref", "x2");
442 Way w3 = new Way();
443 ds.addPrimitive(n);
444 ds.addPrimitive(w1);
445 ds.addPrimitive(w2);
446 ds.addPrimitive(w3);
447 w1.addNode(n);
448 w2.addNode(n);
449 w3.addNode(n);
450
451 MapCSSStyleSource source = new MapCSSStyleSource("node[foo=bar] {refs: join_list(\";\", parent_tags(\"ref\"));}");
452 source.loadStyleSource();
453 assertEquals(1, source.rules.size());
454 Environment e = new Environment(n, new MultiCascade(), Environment.DEFAULT_LAYER, null);
455 assertTrue(source.rules.get(0).matches(e));
456 source.rules.get(0).declaration.execute(e);
457 assertEquals("x2;x10", e.getCascade(Environment.DEFAULT_LAYER).get("refs", null, String.class));
458 }
459
460 @Test
461 void testSort() throws Exception {
462 assertEquals(Arrays.asList(new String[] {"alpha", "beta"}), Functions.sort("beta", "alpha"));
463 Way way1 = TestUtils.newWay("highway=residential name=Alpha alt_name=Beta ref=\"A9;A8\"", new Node(new LatLon(0.001, 0.001)),
464 new Node(new LatLon(0.002, 0.002)));
465
466 MapCSSStyleSource source = new MapCSSStyleSource("way[highway] {sorted: join_list(\",\", sort(tag(\"alt_name\"), tag(\"name\")));}");
467 source.loadStyleSource();
468 assertEquals(1, source.rules.size());
469 Environment e = new Environment(way1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
470 assertTrue(source.rules.get(0).matches(e));
471 source.rules.get(0).declaration.execute(e);
472 assertEquals(Functions.join(",", "Alpha", "Beta"), e.getCascade(Environment.DEFAULT_LAYER).get("sorted", null, String.class));
473
474 source = new MapCSSStyleSource("way[ref] {sorted: join_list(\",\", sort_list(split(\";\", tag(\"ref\"))));}");
475 source.loadStyleSource();
476 e = new Environment(way1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
477 assertTrue(source.rules.get(0).matches(e));
478 source.rules.get(0).declaration.execute(e);
479 assertEquals(Functions.join(",", "A8", "A9"), e.getCascade(Environment.DEFAULT_LAYER).get("sorted", null, String.class));
480 }
481
482 @Test
483 void testUniqueValues() throws Exception {
484 assertEquals(Arrays.asList(new String[] {"alpha", "beta"}),
485 Functions.uniq("alpha", "alpha", "alpha", "beta"));
486 assertEquals(Arrays.asList(new String[] {"one", "two", "three"}),
487 Functions.uniq_list(Arrays.asList(new String[] {"one", "one", "two", "two", "two", "three"})));
488 }
489
490 @Test
491 void testCountRoles() throws Exception {
492 DataSet ds = new DataSet();
493 Way way1 = TestUtils.newWay("highway=residential name=1",
494 new Node(new LatLon(0, 0)), new Node((new LatLon(0.001, 0.001))));
495 for (Node node : way1.getNodes()) {
496 ds.addPrimitive(node);
497 }
498 ds.addPrimitive(way1);
499
500 Relation rel1 = TestUtils.newRelation("type=destination_sign", new RelationMember("", way1));
501 ds.addPrimitive(rel1);
502
503 /* Check with empty role and one object */
504 Environment e = new Environment(rel1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
505 assertEquals(1, Functions.count_roles(e, ""));
506
507 /* Check with non-empty role and one object */
508 e = new Environment(rel1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
509 assertEquals(0, Functions.count_roles(e, "from"));
510
511 /* Check with empty role and two objects */
512 Way way2 = TestUtils.newWay("highway=residential name=2", way1.firstNode(), way1.lastNode());
513 ds.addPrimitive(way2);
514 rel1.addMember(new RelationMember("", way2));
515 e = new Environment(rel1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
516 assertEquals(2, Functions.count_roles(e, ""));
517
518 /* Check with non-empty role and two objects */
519 rel1.setMember(0, new RelationMember("from", way1));
520 e = new Environment(rel1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
521 assertEquals(1, Functions.count_roles(e, "from"));
522
523 /* Check with multiple roles */
524 assertEquals(1, Functions.count_roles(e, "from", "to"));
525
526 /* Check with non-relation */
527 e = new Environment(way1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
528 assertEquals(0, Functions.count_roles(e, "from", "to"));
529
530 /* Check with actual call to mapcss functions */
531 MapCSSStyleSource source = new MapCSSStyleSource("relation[type=destination_sign] {roles: count_roles(\"from\");}");
532 source.loadStyleSource();
533 assertEquals(1, source.rules.size());
534 e = new Environment(rel1, new MultiCascade(), Environment.DEFAULT_LAYER, null);
535 assertTrue(source.rules.get(0).matches(e));
536 source.rules.get(0).declaration.execute(e);
537 assertEquals((Integer) 1, e.getCascade(Environment.DEFAULT_LAYER).get("roles", null, Integer.class));
538 }
539
540 @Test
541 void testSiblingSelectorInterpolation() throws Exception {
542 ChildOrParentSelector s1 = (Selector.ChildOrParentSelector) getParser(
543 "*[tag(\"addr:housenumber\") > child_tag(\"addr:housenumber\")][regexp_test(\"even|odd\", parent_tag(\"addr:interpolation\"))]" +
544 " + *[addr:housenumber]").child_selector();
545 DataSet ds = new DataSet();
546 Node n1 = new Node(new LatLon(1, 2));
547 n1.put("addr:housenumber", "10");
548 Node n2 = new Node(new LatLon(1.1, 2.2));
549 n2.put("addr:housenumber", "100");
550 Node n3 = new Node(new LatLon(1.2, 2.3));
551 n3.put("addr:housenumber", "20");
552 Way w = new Way();
553 w.put("addr:interpolation", "even");
554 ds.addPrimitive(n1);
555 ds.addPrimitive(n2);
556 ds.addPrimitive(n3);
557 ds.addPrimitive(w);
558 w.addNode(n1);
559 w.addNode(n2);
560 w.addNode(n3);
561
562 assertTrue(s1.right.matches(new Environment(n3)));
563 assertTrue(s1.left.matches(new Environment(n2).withChild(n3).withParent(w)));
564 assertTrue(s1.matches(new Environment(n3)));
565 assertFalse(s1.matches(new Environment(n1)));
566 assertFalse(s1.matches(new Environment(n2)));
567 assertFalse(s1.matches(new Environment(w)));
568 }
569
570 @Test
571 void testInvalidBaseSelector() throws Exception {
572 MapCSSStyleSource css = new MapCSSStyleSource("invalid_base[key=value] {}");
573 css.loadStyleSource();
574 assertFalse(css.getErrors().isEmpty());
575 assertTrue(css.getErrors().iterator().next().toString().contains("Unknown MapCSS base selector invalid_base"));
576 }
577
578 @Test
579 void testMinMaxFunctions() throws Exception {
580 MapCSSStyleSource sheet = new MapCSSStyleSource("* {" +
581 "min_value: min(tag(x), tag(y), tag(z)); " +
582 "max_value: max(tag(x), tag(y), tag(z)); " +
583 "max_split: max(split(\";\", tag(widths))); " +
584 "}");
585 sheet.loadStyleSource();
586 MultiCascade mc = new MultiCascade();
587
588 sheet.apply(mc, OsmUtils.createPrimitive("way x=4 y=6 z=8 u=100"), 20, false);
589 assertEquals(Float.valueOf(4.0f), mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", Float.NaN, Float.class));
590 assertEquals(Float.valueOf(8.0f), mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", Float.NaN, Float.class));
591
592 sheet.apply(mc, OsmUtils.createPrimitive("way x=4 y=6 widths=1;2;8;56;3;a"), 20, false);
593 assertEquals(Float.valueOf(4f), mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", -777f, Float.class));
594 assertEquals(Float.valueOf(6f), mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", -777f, Float.class));
595 assertEquals(Float.valueOf(56f), mc.getCascade(Environment.DEFAULT_LAYER).get("max_split", -777f, Float.class));
596 }
597
598 /**
599 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/12549">Bug #12549</a>.
600 * @throws ParseException if a parsing error occurs
601 */
602 @Test
603 void testTicket12549() throws ParseException {
604 Condition condition = getParser("[name =~ /^(?i)(?u)fóo$/]").condition(PRIMITIVE);
605 assertTrue(condition.applies(getEnvironment("name", "fóo")));
606 assertTrue(condition.applies(getEnvironment("name", "fÓo")));
607 condition = getParser("[name =~ /^(\\p{Lower})+$/]").condition(PRIMITIVE);
608 assertFalse(condition.applies(getEnvironment("name", "fóo")));
609 condition = getParser("[name =~ /^(?U)(\\p{Lower})+$/]").condition(PRIMITIVE);
610 assertTrue(condition.applies(getEnvironment("name", "fóo")));
611 assertFalse(condition.applies(getEnvironment("name", "fÓo")));
612 }
613
614 /**
615 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/17053">Bug #17053</a>.
616 */
617 @Test
618 void testTicket17053() {
619 MapCSSStyleSource sheet = new MapCSSStyleSource(
620 "way {\n" +
621 " placement_offset: eval(\n" +
622 " cond(prop(\"placement_value\")=\"right_of:1\",eval((prop(lane_width_forward_1)/2)-prop(lane_offset_forward_1)),\n" +
623 " 0\n" +
624 " )\n" +
625 " );\n" +
626 "}");
627 sheet.loadStyleSource();
628 assertTrue(sheet.getErrors().isEmpty(), sheet.getErrors()::toString);
629 }
630
631 /**
632 * Test parsing zoom expressions
633 * @throws ParseException if a parsing error occurs
634 */
635 @Test
636 void testZoom() throws ParseException {
637 assertNotNull(getParser("|z12").zoom());
638 assertNotNull(getParser("|z12-").zoom());
639 assertNotNull(getParser("|z-12").zoom());
640 assertNotNull(getParser("|z12-16").zoom());
641 }
642
643 /**
644 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/18759">Bug #18759</a>.
645 */
646 @Test
647 void testZoomIAE() {
648 assertThrows(IllegalArgumentException.class, () -> getParser("|z16-15").zoom());
649 }
650
651 /**
652 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/16183">Bug #16183</a>.
653 */
654 @Test
655 void testTicket16183() {
656 MapCSSStyleSource sheet = new MapCSSStyleSource(
657 "area:closed:areaStyle ⧉ area:closed:areaStyle {throwOther: \"xxx\";}");
658 sheet.loadStyleSource();
659 final String rule = sheet.rules.get(0).toString();
660 assertTrue(rule.contains("closed"));
661 assertFalse(rule.contains("areaStyle"));
662 }
663
664 /**
665 * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/19685">Bug #19685</a>.
666 */
667 @Test
668 void testTicket19685() {
669 MapCSSStyleSource sheet = new MapCSSStyleSource("node:connection:foobar {}");
670 sheet.loadStyleSource();
671 assertEquals(1, sheet.getErrors().size());
672 assertEquals("Error at line 1, column 17: Invalid pseudo class specified: foobar", sheet.getErrors().iterator().next().getMessage());
673 }
674}
Note: See TracBrowser for help on using the repository browser.