Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ChildOrParentSelectorTest.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ChildOrParentSelectorTest.groovy	(revision 14062)
+++ 	(revision )
@@ -1,189 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.mappaint.mapcss
-
-import java.util.logging.Logger
-
-import org.junit.*
-import org.openstreetmap.josm.JOSMFixture
-import org.openstreetmap.josm.data.coor.LatLon
-import org.openstreetmap.josm.data.osm.DataSet
-import org.openstreetmap.josm.data.osm.Node
-import org.openstreetmap.josm.data.osm.OsmPrimitiveType
-import org.openstreetmap.josm.data.osm.Relation
-import org.openstreetmap.josm.data.osm.RelationMember
-import org.openstreetmap.josm.data.osm.Way
-import org.openstreetmap.josm.gui.mappaint.Environment
-import org.openstreetmap.josm.gui.mappaint.MultiCascade
-import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector
-import org.openstreetmap.josm.io.OsmReader
-
-class ChildOrParentSelectorTest {
-    static private Logger logger = Logger.getLogger(ChildOrParentSelectorTest.class.getName());
-
-    def DataSet ds;
-
-    @BeforeClass
-    public static void createJOSMFixture(){
-        JOSMFixture.createUnitTestFixture().init()
-    }
-
-    @Before
-    public void setUp() {
-        ds = new DataSet()
-    }
-
-    def relation(id) {
-        def r = new Relation(id,1)
-        ds.addPrimitive(r)
-        return r
-    }
-
-    def node(id) {
-        def n = new Node(id,1)
-        n.setCoor(LatLon.ZERO)
-        ds.addPrimitive(n)
-        return n
-    }
-
-    def way(id){
-        def w = new Way(id,1)
-        ds.addPrimitive(w)
-        return w
-    }
-
-    def ChildOrParentSelector parse(css){
-         MapCSSStyleSource source = new MapCSSStyleSource(css)
-         source.loadStyleSource()
-         assert source.rules.size() == 1
-         return source.rules[0].selector
-    }
-
-    @Test
-    @Ignore
-    public void matches_1() {
-        def css = """
-           relation >[role="my_role"] node {}
-        """
-        ChildOrParentSelector selector = parse(css)
-
-        Relation r = relation(1)
-        Node n = node(1)
-        r.addMember(new RelationMember("my_role", n))
-        Environment e = new Environment().withChild(n)
-
-        assert selector.matches(e)
-    }
-
-    @Test
-    @Ignore
-    public void matches_2() {
-        def css = """
-           relation >["my_role"] node {}
-        """
-        ChildOrParentSelector selector = parse(css)
-
-        Relation r = relation(1)
-        Node n = node(1)
-        r.addMember(new RelationMember("my_role", n))
-        Environment e = new Environment().withChild(n)
-
-        assert selector.matches(e)
-    }
-
-    @Test
-    @Ignore
-    public void matches_3() {
-        def css = """
-           relation >[!"my_role"] node {}
-        """
-        ChildOrParentSelector selector = parse(css)
-
-        Relation r = relation(1)
-        Node n = node(1)
-        r.addMember(new RelationMember("my_role", n))
-        Environment e = new Environment().withChild(n)
-
-        assert !selector.matches(e)
-    }
-
-    @Test
-    @Ignore
-    public void matches_4() {
-        def css = """
-           way < relation {}
-        """
-        ChildOrParentSelector selector = parse(css)
-        assert selector.type == Selector.ChildOrParentSelectorType.PARENT
-
-    }
-    @Test
-    public void matches_5() {
-        def css = """
-           way <[role != "my_role"] relation {text: index();}
-        """
-        ChildOrParentSelector selector = parse(css)
-        assert selector.type == Selector.ChildOrParentSelectorType.PARENT
-
-        Relation r = relation(1)
-        Way w1 = way(1)
-        w1.setNodes([node(11), node(12)])
-
-        Way w2 = way(2)
-        w2.setNodes([node(21), node(22)])
-
-        Way w3 = way(3)
-        w3.setNodes([node(31), node(32)])
-
-        r.addMember(new RelationMember("my_role", w1))
-        r.addMember(new RelationMember("my_role", w2))
-        r.addMember(new RelationMember("another role", w3))
-        r.addMember(new RelationMember("yet another role", w3))
-
-        Environment e = new Environment(r, new MultiCascade(), Environment.DEFAULT_LAYER, null)
-        assert selector.matches(e)
-
-        MapCSSStyleSource source = new MapCSSStyleSource(css)
-        source.loadStyleSource()
-        source.rules[0].declaration.execute(e)
-        assert Float.valueOf(3f).equals(e.getCascade(Environment.DEFAULT_LAYER).get("text", null, Float.class))
-    }
-
-    @Test
-    public void matches_6() {
-        def css = """
-           relation >[role != "my_role"] way {}
-        """
-        ChildOrParentSelector selector = parse(css)
-
-        Relation r = relation(1)
-        Way w1 = way(1)
-        w1.setNodes([node(11), node(12)])
-
-        Way w2 = way(2)
-        w2.setNodes([node(21), node(22)])
-
-        Way w3 = way(3)
-        w3.setNodes([node(31), node(32)])
-
-        r.addMember(new RelationMember("my_role", w1))
-        r.addMember(new RelationMember("my_role", w2))
-        r.addMember(new RelationMember("another role", w3))
-
-        Environment e = new Environment(w1)
-        assert !selector.matches(e)
-
-        e = new Environment(w2)
-        assert !selector.matches(e)
-
-        e = new Environment(w3)
-        assert selector.matches(e)
-    }
-
-    @Test
-    public void testContains() throws Exception {
-        def ds = OsmReader.parseDataSet(new FileInputStream("data_nodist/amenity-in-amenity.osm"), null)
-        def css = parse("node[tag(\"amenity\") = parent_tag(\"amenity\")] ∈ *[amenity] {}")
-        assert css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.WAY)))
-        assert css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.RELATION)))
-    }
-}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ChildOrParentSelectorTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ChildOrParentSelectorTest.java	(revision 14064)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ChildOrParentSelectorTest.java	(revision 14064)
@@ -0,0 +1,195 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.mapcss;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileInputStream;
+import java.util.Arrays;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.mappaint.Environment;
+import org.openstreetmap.josm.gui.mappaint.MultiCascade;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
+import org.openstreetmap.josm.io.OsmReader;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Unit tests of {@link ChildOrParentSelector}.
+ */
+public class ChildOrParentSelectorTest {
+
+    private DataSet ds;
+
+    /**
+     * Setup rule
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().projection();
+
+    /**
+     * Setup test
+     */
+    @Before
+    public void setUp() {
+        ds = new DataSet();
+    }
+
+    Relation relation(int id) {
+        Relation r = new Relation(id, 1);
+        ds.addPrimitive(r);
+        return r;
+    }
+
+    Node node(int id) {
+        Node n = new Node(id, 1);
+        n.setCoor(LatLon.ZERO);
+        ds.addPrimitive(n);
+        return n;
+    }
+
+    Way way(int id) {
+        Way w = new Way(id, 1);
+        ds.addPrimitive(w);
+        return w;
+    }
+
+    ChildOrParentSelector parse(String css) {
+         MapCSSStyleSource source = new MapCSSStyleSource(css);
+         source.loadStyleSource();
+         assertEquals(1, source.rules.size());
+         return (ChildOrParentSelector) source.rules.get(0).selector;
+    }
+
+    @Test
+    @Ignore
+    public void matches_1() {
+        String css = "relation >[role=\"my_role\"] node {}";
+        ChildOrParentSelector selector = parse(css);
+
+        Relation r = relation(1);
+        Node n = node(1);
+        r.addMember(new RelationMember("my_role", n));
+        Environment e = new Environment().withChild(n);
+
+        assertTrue(selector.matches(e));
+    }
+
+    @Test
+    @Ignore
+    public void matches_2() {
+        String css = "relation >[\"my_role\"] node {}";
+        ChildOrParentSelector selector = parse(css);
+
+        Relation r = relation(1);
+        Node n = node(1);
+        r.addMember(new RelationMember("my_role", n));
+        Environment e = new Environment().withChild(n);
+
+        assertTrue(selector.matches(e));
+    }
+
+    @Test
+    @Ignore
+    public void matches_3() {
+        String css = "relation >[!\"my_role\"] node {}";
+        ChildOrParentSelector selector = parse(css);
+
+        Relation r = relation(1);
+        Node n = node(1);
+        r.addMember(new RelationMember("my_role", n));
+        Environment e = new Environment().withChild(n);
+
+        assertFalse(selector.matches(e));
+    }
+
+    @Test
+    @Ignore
+    public void matches_4() {
+        String css = "way < relation {}";
+        ChildOrParentSelector selector = parse(css);
+        assertEquals(Selector.ChildOrParentSelectorType.PARENT, selector.type);
+
+    }
+
+    @Test
+    public void matches_5() {
+        String css = "way <[role != \"my_role\"] relation {text: index();}";
+        ChildOrParentSelector selector = parse(css);
+        assertEquals(Selector.ChildOrParentSelectorType.PARENT, selector.type);
+
+        Relation r = relation(1);
+        Way w1 = way(1);
+        w1.setNodes(Arrays.asList(node(11), node(12)));
+
+        Way w2 = way(2);
+        w2.setNodes(Arrays.asList(node(21), node(22)));
+
+        Way w3 = way(3);
+        w3.setNodes(Arrays.asList(node(31), node(32)));
+
+        r.addMember(new RelationMember("my_role", w1));
+        r.addMember(new RelationMember("my_role", w2));
+        r.addMember(new RelationMember("another role", w3));
+        r.addMember(new RelationMember("yet another role", w3));
+
+        Environment e = new Environment(r, new MultiCascade(), Environment.DEFAULT_LAYER, null);
+        assertTrue(selector.matches(e));
+
+        MapCSSStyleSource source = new MapCSSStyleSource(css);
+        source.loadStyleSource();
+        source.rules.get(0).declaration.execute(e);
+        assertEquals(Float.valueOf(3f), e.getCascade(Environment.DEFAULT_LAYER).get("text", null, Float.class));
+    }
+
+    @Test
+    public void matches_6() {
+        String css = "relation >[role != \"my_role\"] way {}";
+        ChildOrParentSelector selector = parse(css);
+
+        Relation r = relation(1);
+        Way w1 = way(1);
+        w1.setNodes(Arrays.asList(node(11), node(12)));
+
+        Way w2 = way(2);
+        w2.setNodes(Arrays.asList(node(21), node(22)));
+
+        Way w3 = way(3);
+        w3.setNodes(Arrays.asList(node(31), node(32)));
+
+        r.addMember(new RelationMember("my_role", w1));
+        r.addMember(new RelationMember("my_role", w2));
+        r.addMember(new RelationMember("another role", w3));
+
+        Environment e = new Environment(w1);
+        assertFalse(selector.matches(e));
+
+        e = new Environment(w2);
+        assertFalse(selector.matches(e));
+
+        e = new Environment(w3);
+        assertTrue(selector.matches(e));
+    }
+
+    @Test
+    public void testContains() throws Exception {
+        ds = OsmReader.parseDataSet(new FileInputStream("data_nodist/amenity-in-amenity.osm"), null);
+        ChildOrParentSelector css = parse("node[tag(\"amenity\") = parent_tag(\"amenity\")] ∈ *[amenity] {}");
+        assertTrue(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.WAY))));
+        assertTrue(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.RELATION))));
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.groovy	(revision 14062)
+++ 	(revision )
@@ -1,102 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.mappaint.mapcss;
-
-import static groovy.test.GroovyAssert.shouldFail
-import static org.junit.Assert.*
-
-import org.junit.*
-import org.openstreetmap.josm.JOSMFixture
-import org.openstreetmap.josm.data.coor.LatLon
-import org.openstreetmap.josm.data.osm.DataSet
-import org.openstreetmap.josm.data.osm.Node
-import org.openstreetmap.josm.data.osm.Relation
-import org.openstreetmap.josm.data.osm.RelationMember
-import org.openstreetmap.josm.gui.mappaint.Environment
-import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context
-import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyMatchType
-
-class KeyConditionTest {
-
-    def DataSet ds;
-
-    @BeforeClass
-    public static void createJOSMFixture(){
-        JOSMFixture.createUnitTestFixture().init()
-    }
-
-    @Before
-    public void setUp() {
-        ds = new DataSet()
-    }
-
-    def relation(id) {
-        def r = new Relation(id,1)
-        ds.addPrimitive(r)
-        return r
-    }
-
-    def node(id) {
-        def n = new Node(id,1)
-        n.setCoor(LatLon.ZERO)
-        ds.addPrimitive(n)
-        return n
-    }
-
-    @Test
-    public void create() {
-
-        // ["a label"]
-        Condition c = ConditionFactory.createKeyCondition("a key", false, KeyMatchType.FALSE, Context.PRIMITIVE)
-        // ["a label"?]
-        c = ConditionFactory.createKeyCondition("a key", false, KeyMatchType.TRUE, Context.PRIMITIVE)
-        // [!"a label"]
-        c = ConditionFactory.createKeyCondition("a key", true, KeyMatchType.FALSE, Context.PRIMITIVE)
-        // [!"a label"?]
-        c = ConditionFactory.createKeyCondition("a key", true, KeyMatchType.TRUE, Context.PRIMITIVE)
-
-        // ["a label"]
-        c = ConditionFactory.createKeyCondition("a key", false, null, Context.LINK)
-        // [!"a label"]
-        c = ConditionFactory.createKeyCondition("a key", true, null, Context.LINK)
-
-        shouldFail(MapCSSException) {
-            // ["a label"?]
-           c = ConditionFactory.createKeyCondition("a key", false, KeyMatchType.TRUE, Context.LINK)
-        }
-
-        shouldFail(MapCSSException) {
-            // [!"a label"?]
-            c = ConditionFactory.createKeyCondition("a key", true, KeyMatchType.TRUE, Context.LINK)
-        }
-    }
-
-    @Test
-    public void applies_1() {
-        Relation r = relation(1)
-        Node n = node(1)
-        r.addMember(new RelationMember("my_role", n))
-
-        Environment e = new Environment(n).withParent(r).withIndex(0, r.membersCount).withLinkContext()
-
-        Condition cond = ConditionFactory.createKeyCondition("my_role", false, null, Context.LINK)
-        assert cond.applies(e)
-
-        cond = ConditionFactory.createKeyCondition("my_role", true, null, Context.LINK)
-        assert !cond.applies(e)
-    }
-
-    @Test
-    public void applies_2() {
-        Relation r = relation(1)
-        Node n = node(1)
-        r.addMember(new RelationMember("my_role", n))
-
-        Environment e = new Environment(n).withParent(r).withIndex(0, r.membersCount).withLinkContext()
-
-        Condition cond = ConditionFactory.createKeyCondition("another_role", false, null, Context.LINK)
-        assert !cond.applies(e)
-
-        cond = ConditionFactory.createKeyCondition("another_role", true, null, Context.LINK)
-        assert cond.applies(e)
-    }
-}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.java	(revision 14064)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.java	(revision 14064)
@@ -0,0 +1,129 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.mapcss;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.gui.mappaint.Environment;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyCondition;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyMatchType;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.tools.Logging;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Unit tests of {@link KeyCondition}.
+ */
+public class KeyConditionTest {
+
+    private DataSet ds;
+
+    /**
+     * Setup rule
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().projection();
+
+    /**
+     * Setup test
+     */
+    @Before
+    public void setUp() {
+        ds = new DataSet();
+    }
+
+    Relation relation(int id) {
+        Relation r = new Relation(id, 1);
+        ds.addPrimitive(r);
+        return r;
+    }
+
+    Node node(int id) {
+        Node n = new Node(id, 1);
+        n.setCoor(LatLon.ZERO);
+        ds.addPrimitive(n);
+        return n;
+    }
+
+    private static void shouldFail(Runnable r) {
+        try {
+            r.run();
+            fail("should throw exception");
+        } catch (MapCSSException e) {
+            Logging.trace(e);
+        }
+    }
+
+    /**
+     * Test {@link ConditionFactory#createKeyCondition}.
+     */
+    @Test
+    public void create() {
+
+        // ["a label"]
+        ConditionFactory.createKeyCondition("a key", false, KeyMatchType.FALSE, Context.PRIMITIVE);
+        // ["a label"?]
+        ConditionFactory.createKeyCondition("a key", false, KeyMatchType.TRUE, Context.PRIMITIVE);
+        // [!"a label"]
+        ConditionFactory.createKeyCondition("a key", true, KeyMatchType.FALSE, Context.PRIMITIVE);
+        // [!"a label"?]
+        ConditionFactory.createKeyCondition("a key", true, KeyMatchType.TRUE, Context.PRIMITIVE);
+
+        // ["a label"]
+        ConditionFactory.createKeyCondition("a key", false, null, Context.LINK);
+        // [!"a label"]
+        ConditionFactory.createKeyCondition("a key", true, null, Context.LINK);
+
+        // ["a label"?]
+        shouldFail(() ->
+           ConditionFactory.createKeyCondition("a key", false, KeyMatchType.TRUE, Context.LINK)
+        );
+
+        // [!"a label"?]
+        shouldFail(() ->
+            ConditionFactory.createKeyCondition("a key", true, KeyMatchType.TRUE, Context.LINK)
+        );
+    }
+
+    @Test
+    public void applies_1() {
+        Relation r = relation(1);
+        Node n = node(1);
+        r.addMember(new RelationMember("my_role", n));
+
+        Environment e = new Environment(n).withParent(r).withIndex(0, r.getMembersCount()).withLinkContext();
+
+        Condition cond = ConditionFactory.createKeyCondition("my_role", false, null, Context.LINK);
+        assertTrue(cond.applies(e));
+
+        cond = ConditionFactory.createKeyCondition("my_role", true, null, Context.LINK);
+        assertFalse(cond.applies(e));
+    }
+
+    @Test
+    public void applies_2() {
+        Relation r = relation(1);
+        Node n = node(1);
+        r.addMember(new RelationMember("my_role", n));
+
+        Environment e = new Environment(n).withParent(r).withIndex(0, r.getMembersCount()).withLinkContext();
+
+        Condition cond = ConditionFactory.createKeyCondition("another_role", false, null, Context.LINK);
+        assertFalse(cond.applies(e));
+
+        cond = ConditionFactory.createKeyCondition("another_role", true, null, Context.LINK);
+        assertTrue(cond.applies(e));
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyValueConditionTest.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyValueConditionTest.groovy	(revision 14062)
+++ 	(revision )
@@ -1,118 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.mappaint.mapcss;
-
-import static groovy.test.GroovyAssert.shouldFail
-
-import org.junit.*
-import org.openstreetmap.josm.JOSMFixture
-import org.openstreetmap.josm.data.coor.LatLon
-import org.openstreetmap.josm.data.osm.DataSet
-import org.openstreetmap.josm.data.osm.Node
-import org.openstreetmap.josm.data.osm.OsmUtils
-import org.openstreetmap.josm.data.osm.Relation
-import org.openstreetmap.josm.data.osm.RelationMember
-import org.openstreetmap.josm.gui.mappaint.Environment
-import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context
-import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.Op
-import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser
-
-class KeyValueConditionTest {
-
-    def DataSet ds;
-
-    @BeforeClass
-    public static void createJOSMFixture(){
-        JOSMFixture.createUnitTestFixture().init()
-    }
-
-    @Before
-    public void setUp() {
-        ds = new DataSet()
-    }
-
-    def relation(id) {
-        def r = new Relation(id,1)
-        ds.addPrimitive(r)
-        return r
-    }
-
-    def node(id) {
-        def n = new Node(id,1)
-        n.setCoor(LatLon.ZERO)
-        ds.addPrimitive(n)
-        return n
-    }
-
-    @Test
-    public void create() {
-        Condition c = ConditionFactory.createKeyValueCondition("a key", "a value", Op.EQ, Context.PRIMITIVE, false)
-
-        c = ConditionFactory.createKeyValueCondition("role", "a role", Op.EQ, Context.LINK, false)
-        c = ConditionFactory.createKeyValueCondition("RoLe", "a role", Op.EQ, Context.LINK, false)
-
-        shouldFail(MapCSSException) {
-            c = ConditionFactory.createKeyValueCondition("an arbitry tag", "a role", Op.EQ, Context.LINK, false)
-        }
-    }
-
-    @Test
-    public void applies_1() {
-        Relation r = relation(1)
-        Node n = node(1)
-        r.addMember(new RelationMember("my_role", n))
-
-        Environment e = new Environment(n).withParent(r).withLinkContext().withIndex(0, r.membersCount)
-
-        Condition cond = new ConditionFactory.RoleCondition("my_role", Op.EQ)
-        assert cond.applies(e)
-
-        cond = new ConditionFactory.RoleCondition("another_role", Op.EQ)
-        assert !cond.applies(e)
-    }
-
-    @Test
-    public void applies_2() {
-        Relation r = relation(1)
-        Node n = node(1)
-        r.addMember(new RelationMember("my_role", n))
-
-        Environment e = new Environment(n).withParent(r).withIndex(0, r.membersCount).withLinkContext()
-
-        Condition cond = ConditionFactory.createKeyValueCondition("role", "my_role", Op.NEQ, Context.LINK, false)
-        assert !cond.applies(e)
-
-        cond = ConditionFactory.createKeyValueCondition("role", "another_role", Op.NEQ, Context.LINK, false)
-        assert cond.applies(e)
-    }
-
-    @Test
-    public void testKeyRegexValueRegex() throws Exception {
-        def selPos = new MapCSSParser(new StringReader("*[/^source/ =~ /.*,.*/]")).selector()
-        def selNeg = new MapCSSParser(new StringReader("*[/^source/ !~ /.*,.*/]")).selector()
-        assert !selPos.matches(new Environment(OsmUtils.createPrimitive("way foo=bar")))
-        assert selPos.matches(new Environment(OsmUtils.createPrimitive("way source=1,2")))
-        assert selPos.matches(new Environment(OsmUtils.createPrimitive("way source_foo_bar=1,2")))
-        assert !selPos.matches(new Environment(OsmUtils.createPrimitive("way source=1")))
-        assert !selPos.matches(new Environment(OsmUtils.createPrimitive("way source=1")))
-        assert !selNeg.matches(new Environment(OsmUtils.createPrimitive("way source=1,2")))
-        assert !selNeg.matches(new Environment(OsmUtils.createPrimitive("way foo=bar source=1,2")))
-        assert selNeg.matches(new Environment(OsmUtils.createPrimitive("way foo=bar source=baz")))
-        assert selNeg.matches(new Environment(OsmUtils.createPrimitive("way foo=bar src=1,2")))
-    }
-
-    @Test
-    public void testValueFive() throws Exception {
-        // ticket #5985
-        def sel = new MapCSSParser(new StringReader("*[width=5]")).selector()
-        assert sel.matches(new Environment(OsmUtils.createPrimitive("way highway=track width=5")))
-        assert !sel.matches(new Environment(OsmUtils.createPrimitive("way highway=track width=2")))
-    }
-
-    @Test
-    public void testValueZero() throws Exception {
-        // ticket #12267
-        def sel = new MapCSSParser(new StringReader("*[frequency=0]")).selector()
-        assert sel.matches(new Environment(OsmUtils.createPrimitive("way railway=rail frequency=0")))
-        assert !sel.matches(new Environment(OsmUtils.createPrimitive("way railway=rail frequency=50")))
-    }
-}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyValueConditionTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyValueConditionTest.java	(revision 14064)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyValueConditionTest.java	(revision 14064)
@@ -0,0 +1,145 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.mapcss;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.StringReader;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmUtils;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.gui.mappaint.Environment;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyValueCondition;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.Op;
+import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.tools.Logging;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Unit tests of {@link KeyValueCondition}.
+ */
+public class KeyValueConditionTest {
+
+    private DataSet ds;
+
+    /**
+     * Setup rule
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().projection();
+
+    /**
+     * Setup test
+     */
+    @Before
+    public void setUp() {
+        ds = new DataSet();
+    }
+
+    Relation relation(int id) {
+        Relation r = new Relation(id, 1);
+        ds.addPrimitive(r);
+        return r;
+    }
+
+    Node node(int id) {
+        Node n = new Node(id, 1);
+        n.setCoor(LatLon.ZERO);
+        ds.addPrimitive(n);
+        return n;
+    }
+
+    private static void shouldFail(Runnable r) {
+        try {
+            r.run();
+            fail("should throw exception");
+        } catch (MapCSSException e) {
+            Logging.trace(e);
+        }
+    }
+
+    @Test
+    public void create() {
+        ConditionFactory.createKeyValueCondition("a key", "a value", Op.EQ, Context.PRIMITIVE, false);
+
+        ConditionFactory.createKeyValueCondition("role", "a role", Op.EQ, Context.LINK, false);
+        ConditionFactory.createKeyValueCondition("RoLe", "a role", Op.EQ, Context.LINK, false);
+
+        shouldFail(() ->
+            ConditionFactory.createKeyValueCondition("an arbitry tag", "a role", Op.EQ, Context.LINK, false)
+        );
+    }
+
+    @Test
+    public void applies_1() {
+        Relation r = relation(1);
+        Node n = node(1);
+        r.addMember(new RelationMember("my_role", n));
+
+        Environment e = new Environment(n).withParent(r).withLinkContext().withIndex(0, r.getMembersCount());
+
+        Condition cond = new ConditionFactory.RoleCondition("my_role", Op.EQ);
+        assertTrue(cond.applies(e));
+
+        cond = new ConditionFactory.RoleCondition("another_role", Op.EQ);
+        assertFalse(cond.applies(e));
+    }
+
+    @Test
+    public void applies_2() {
+        Relation r = relation(1);
+        Node n = node(1);
+        r.addMember(new RelationMember("my_role", n));
+
+        Environment e = new Environment(n).withParent(r).withIndex(0, r.getMembersCount()).withLinkContext();
+
+        Condition cond = ConditionFactory.createKeyValueCondition("role", "my_role", Op.NEQ, Context.LINK, false);
+        assertFalse(cond.applies(e));
+
+        cond = ConditionFactory.createKeyValueCondition("role", "another_role", Op.NEQ, Context.LINK, false);
+        assertTrue(cond.applies(e));
+    }
+
+    @Test
+    public void testKeyRegexValueRegex() throws Exception {
+        Selector selPos = new MapCSSParser(new StringReader("*[/^source/ =~ /.*,.*/]")).selector();
+        Selector selNeg = new MapCSSParser(new StringReader("*[/^source/ !~ /.*,.*/]")).selector();
+        assertFalse(selPos.matches(new Environment(OsmUtils.createPrimitive("way foo=bar"))));
+        assertTrue(selPos.matches(new Environment(OsmUtils.createPrimitive("way source=1,2"))));
+        assertTrue(selPos.matches(new Environment(OsmUtils.createPrimitive("way source_foo_bar=1,2"))));
+        assertFalse(selPos.matches(new Environment(OsmUtils.createPrimitive("way source=1"))));
+        assertFalse(selPos.matches(new Environment(OsmUtils.createPrimitive("way source=1"))));
+        assertFalse(selNeg.matches(new Environment(OsmUtils.createPrimitive("way source=1,2"))));
+        assertFalse(selNeg.matches(new Environment(OsmUtils.createPrimitive("way foo=bar source=1,2"))));
+        assertTrue(selNeg.matches(new Environment(OsmUtils.createPrimitive("way foo=bar source=baz"))));
+        assertTrue(selNeg.matches(new Environment(OsmUtils.createPrimitive("way foo=bar src=1,2"))));
+    }
+
+    @Test
+    public void testValueFive() throws Exception {
+        // ticket #5985
+        Selector sel = new MapCSSParser(new StringReader("*[width=5]")).selector();
+        assertTrue(sel.matches(new Environment(OsmUtils.createPrimitive("way highway=track width=5"))));
+        assertFalse(sel.matches(new Environment(OsmUtils.createPrimitive("way highway=track width=2"))));
+    }
+
+    @Test
+    public void testValueZero() throws Exception {
+        // ticket #12267
+        Selector sel = new MapCSSParser(new StringReader("*[frequency=0]")).selector();
+        assertTrue(sel.matches(new Environment(OsmUtils.createPrimitive("way railway=rail frequency=0"))));
+        assertFalse(sel.matches(new Environment(OsmUtils.createPrimitive("way railway=rail frequency=50"))));
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.groovy	(revision 14062)
+++ 	(revision )
@@ -1,451 +1,0 @@
-package org.openstreetmap.josm.gui.mappaint.mapcss
-
-import java.awt.Color
-
-import org.junit.Before
-import org.junit.Test
-import org.openstreetmap.josm.JOSMFixture
-import org.openstreetmap.josm.data.coor.LatLon
-import org.openstreetmap.josm.data.osm.DataSet
-import org.openstreetmap.josm.data.osm.Node
-import org.openstreetmap.josm.data.osm.OsmUtils
-import org.openstreetmap.josm.data.osm.Way
-import org.openstreetmap.josm.gui.mappaint.Environment
-import org.openstreetmap.josm.gui.mappaint.MultiCascade
-import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.ClassCondition
-import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyCondition
-import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyMatchType
-import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyValueCondition
-import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.Op
-import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.PseudoClassCondition
-import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.SimpleKeyValueCondition
-import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser
-import org.openstreetmap.josm.tools.ColorHelper
-
-class MapCSSParserTest {
-
-    protected static Environment getEnvironment(String key, String value) {
-        return new Environment(OsmUtils.createPrimitive("way " + key + "=" + value))
-    }
-
-    protected static MapCSSParser getParser(String stringToParse) {
-        return new MapCSSParser(new StringReader(stringToParse));
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
-    @Test
-    public void testKothicStylesheets() throws Exception {
-        new MapCSSParser(new URL("https://raw.githubusercontent.com/kothic/kothic/master/src/styles/default.mapcss").openStream(), "UTF-8")
-        new MapCSSParser(new URL("https://raw.githubusercontent.com/kothic/kothic/master/src/styles/mapink.mapcss").openStream(), "UTF-8")
-    }
-
-    @Test
-    public void testDeclarations() {
-        getParser("{ opacity: 0.5; color: rgb(1.0, 0.0, 0.0); }").declaration()
-        getParser("{ set tag=value; }").declaration() //set a tag
-        getParser("{ set tag; }").declaration() // set a tag to 'yes'
-        getParser("{ opacity: eval(\"tag('population')/100000\"); }").declaration()
-        getParser("{ set width_in_metres=eval(\"tag('lanes')*3\"); }").declaration()
-    }
-
-    @Test
-    public void testClassCondition() throws Exception {
-        def conditions = ((Selector.GeneralSelector) getParser("way[name=X].highway:closed").selector()).conds
-        assert conditions.get(0) instanceof SimpleKeyValueCondition
-        assert conditions.get(0).applies(getEnvironment("name", "X"))
-        assert conditions.get(1) instanceof ClassCondition
-        assert conditions.get(2) instanceof PseudoClassCondition
-        assert !conditions.get(2).applies(getEnvironment("name", "X"))
-    }
-
-    @Test
-    public void testPseudoClassCondition() throws Exception {
-        def c1 = ((Selector.GeneralSelector) getParser("way!:area-style").selector()).conds.get(0)
-        def c2 = ((Selector.GeneralSelector) getParser("way!:areaStyle").selector()).conds.get(0)
-        def c3 = ((Selector.GeneralSelector) getParser("way!:area_style").selector()).conds.get(0)
-        assert c1.toString() == "!:areaStyle"
-        assert c2.toString() == "!:areaStyle"
-        assert c3.toString() == "!:areaStyle"
-    }
-
-    @Test
-    public void testClassMatching() throws Exception {
-        def css = new MapCSSStyleSource("" +
-                "way[highway=footway] { set .path; color: #FF6644; width: 2; }\n" +
-                "way[highway=path]    { set path; color: brown; width: 2; }\n" +
-                "way[\"set\"=escape]  {  }\n" +
-                "way.path             { text:auto; text-color: green; text-position: line; text-offset: 5; }\n" +
-                "way!.path            { color: orange; }\n"
-        )
-        css.loadStyleSource()
-        assert css.getErrors().isEmpty()
-        def mc1 = new MultiCascade()
-        css.apply(mc1, OsmUtils.createPrimitive("way highway=path"), 1, false);
-        assert "green".equals(mc1.getCascade("default").get("text-color", null, String.class))
-        assert "brown".equals(mc1.getCascade("default").get("color", null, String.class))
-        def mc2 = new MultiCascade()
-        css.apply(mc2, OsmUtils.createPrimitive("way highway=residential"), 1, false);
-        assert "orange".equals(mc2.getCascade("default").get("color", null, String.class))
-        assert mc2.getCascade("default").get("text-color", null, String.class) == null
-        def mc3 = new MultiCascade()
-        css.apply(mc3, OsmUtils.createPrimitive("way highway=footway"), 1, false);
-        assert ColorHelper.html2color("#FF6644").equals(mc3.getCascade("default").get("color", null, Color.class))
-    }
-
-    @Test
-    public void testEqualCondition() throws Exception {
-        def condition = (SimpleKeyValueCondition) getParser("[surface=paved]").condition(Condition.Context.PRIMITIVE)
-        assert condition instanceof SimpleKeyValueCondition
-        assert "surface".equals(condition.k)
-        assert "paved".equals(condition.v)
-        assert condition.applies(getEnvironment("surface", "paved"))
-        assert !condition.applies(getEnvironment("surface", "unpaved"))
-    }
-
-    @Test
-    public void testNotEqualCondition() throws Exception {
-        def condition = (KeyValueCondition) getParser("[surface!=paved]").condition(Condition.Context.PRIMITIVE)
-        assert Op.NEQ.equals(condition.op)
-        assert !condition.applies(getEnvironment("surface", "paved"))
-        assert condition.applies(getEnvironment("surface", "unpaved"))
-    }
-
-    @Test
-    public void testRegexCondition() throws Exception {
-        def condition = (KeyValueCondition) getParser("[surface=~/paved|unpaved/]").condition(Condition.Context.PRIMITIVE)
-        assert Op.REGEX.equals(condition.op)
-        assert condition.applies(getEnvironment("surface", "unpaved"))
-        assert !condition.applies(getEnvironment("surface", "grass"))
-    }
-
-    @Test
-    public void testRegexConditionParenthesis() throws Exception {
-        def condition = (KeyValueCondition) getParser("[name =~ /^\\(foo\\)/]").condition(Condition.Context.PRIMITIVE)
-        assert condition.applies(getEnvironment("name", "(foo)"))
-        assert !condition.applies(getEnvironment("name", "foo"))
-        assert !condition.applies(getEnvironment("name", "((foo))"))
-    }
-
-    @Test
-    public void testNegatedRegexCondition() throws Exception {
-        def condition = (KeyValueCondition) getParser("[surface!~/paved|unpaved/]").condition(Condition.Context.PRIMITIVE)
-        assert Op.NREGEX.equals(condition.op)
-        assert !condition.applies(getEnvironment("surface", "unpaved"))
-        assert condition.applies(getEnvironment("surface", "grass"))
-    }
-
-    @Test
-    public void testBeginsEndsWithCondition() throws Exception {
-        def condition = (KeyValueCondition) getParser('[foo ^= bar]').condition(Condition.Context.PRIMITIVE)
-        assert Op.BEGINS_WITH.equals(condition.op)
-        assert condition.applies(getEnvironment("foo", "bar123"))
-        assert !condition.applies(getEnvironment("foo", "123bar"))
-        assert !condition.applies(getEnvironment("foo", "123bar123"))
-        condition = (KeyValueCondition) getParser('[foo $= bar]').condition(Condition.Context.PRIMITIVE)
-        assert Op.ENDS_WITH.equals(condition.op)
-        assert !condition.applies(getEnvironment("foo", "bar123"))
-        assert condition.applies(getEnvironment("foo", "123bar"))
-        assert !condition.applies(getEnvironment("foo", "123bar123"))
-    }
-
-    @Test
-    public void testOneOfCondition() throws Exception {
-        def condition = getParser('[vending~=stamps]').condition(Condition.Context.PRIMITIVE)
-        assert condition.applies(getEnvironment("vending", "stamps"))
-        assert condition.applies(getEnvironment("vending", "bar;stamps;foo"))
-        assert !condition.applies(getEnvironment("vending", "every;thing;else"))
-        assert !condition.applies(getEnvironment("vending", "or_nothing"))
-    }
-
-    @Test
-    public void testStandardKeyCondition() throws Exception {
-        def c1 = (KeyCondition) getParser("[ highway ]").condition(Condition.Context.PRIMITIVE)
-        assert KeyMatchType.EQ.equals(c1.matchType)
-        assert c1.applies(getEnvironment("highway", "unclassified"))
-        assert !c1.applies(getEnvironment("railway", "rail"))
-        def c2 = (KeyCondition) getParser("[\"/slash/\"]").condition(Condition.Context.PRIMITIVE)
-        assert KeyMatchType.EQ.equals(c2.matchType)
-        assert c2.applies(getEnvironment("/slash/", "yes"))
-        assert !c2.applies(getEnvironment("\"slash\"", "no"))
-    }
-
-    @Test
-    public void testYesNoKeyCondition() throws Exception {
-        def c1 = (KeyCondition) getParser("[oneway?]").condition(Condition.Context.PRIMITIVE)
-        def c2 = (KeyCondition) getParser("[oneway?!]").condition(Condition.Context.PRIMITIVE)
-        def c3 = (KeyCondition) getParser("[!oneway?]").condition(Condition.Context.PRIMITIVE)
-        def c4 = (KeyCondition) getParser("[!oneway?!]").condition(Condition.Context.PRIMITIVE)
-        def yes = getEnvironment("oneway", "yes")
-        def no = getEnvironment("oneway", "no")
-        def none = getEnvironment("no-oneway", "foo")
-        assert c1.applies(yes)
-        assert !c1.applies(no)
-        assert !c1.applies(none)
-        assert !c2.applies(yes)
-        assert c2.applies(no)
-        assert !c2.applies(none)
-        assert !c3.applies(yes)
-        assert c3.applies(no)
-        assert c3.applies(none)
-        assert c4.applies(yes)
-        assert !c4.applies(no)
-        assert c4.applies(none)
-    }
-
-    @Test
-    public void testRegexKeyCondition() throws Exception {
-        def c1 = (KeyCondition) getParser("[/.*:(backward|forward)\$/]").condition(Condition.Context.PRIMITIVE)
-        assert KeyMatchType.REGEX.equals(c1.matchType)
-        assert !c1.applies(getEnvironment("lanes", "3"))
-        assert c1.applies(getEnvironment("lanes:forward", "3"))
-        assert c1.applies(getEnvironment("lanes:backward", "3"))
-        assert !c1.applies(getEnvironment("lanes:foobar", "3"))
-    }
-
-    @Test
-    public void testNRegexKeyConditionSelector() throws Exception {
-        def s1 = getParser("*[sport][tourism != hotel]").selector()
-        assert s1.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar")))
-        assert !s1.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar tourism=hotel")))
-        def s2 = getParser("*[sport][tourism != hotel][leisure !~ /^(sports_centre|stadium|)\$/]").selector()
-        assert s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar")))
-        assert !s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar tourism=hotel")))
-        assert !s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar leisure=stadium")))
-    }
-
-    @Test
-    public void testKeyKeyCondition() throws Exception {
-        def c1 = (KeyValueCondition) getParser("[foo = *bar]").condition(Condition.Context.PRIMITIVE)
-        def w1 = new Way()
-        w1.put("foo", "123")
-        w1.put("bar", "456")
-        assert !c1.applies(new Environment(w1))
-        w1.put("bar", "123")
-        assert c1.applies(new Environment(w1))
-        def c2 = (KeyValueCondition) getParser("[foo =~ */bar/]").condition(Condition.Context.PRIMITIVE)
-        def w2 = new Way(w1)
-        w2.put("bar", "[0-9]{3}")
-        assert c2.applies(new Environment(w2))
-        w2.put("bar", "[0-9]")
-        assert c2.applies(new Environment(w2))
-        w2.put("bar", "^[0-9]\$")
-        assert !c2.applies(new Environment(w2))
-    }
-
-    @Test
-    public void testParentTag() throws Exception {
-        def c1 = getParser("way[foo] > node[tag(\"foo\")=parent_tag(\"foo\")] {}").child_selector()
-        def ds = new DataSet()
-        def w1 = new Way()
-        def w2 = new Way()
-        def n1 = new Node(new LatLon(1, 1))
-        def n2 = new Node(new LatLon(2, 2))
-        w1.put("foo", "123")
-        w2.put("foo", "123")
-        n1.put("foo", "123")
-        n2.put("foo", "0")
-        ds.addPrimitive(w1)
-        ds.addPrimitive(n1)
-        ds.addPrimitive(n2)
-        w1.addNode(n1)
-        w2.addNode(n2)
-        assert c1.matches(new Environment(n1))
-        assert !c1.matches(new Environment(n2))
-        assert !c1.matches(new Environment(w1))
-        assert !c1.matches(new Environment(w2))
-        n1.put("foo", "0")
-        assert !c1.matches(new Environment(n1))
-        n1.put("foo", "123")
-        assert c1.matches(new Environment(n1))
-    }
-
-    @Test
-    public void testTicket8568() throws Exception {
-        def sheet = new MapCSSStyleSource("" +
-                "way { width: 5; }\n" +
-                "way[keyA], way[keyB] { width: eval(prop(width)+10); }")
-        sheet.loadStyleSource()
-        def mc = new MultiCascade()
-        sheet.apply(mc, OsmUtils.createPrimitive("way foo=bar"), 20, false)
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 5
-        sheet.apply(mc, OsmUtils.createPrimitive("way keyA=true"), 20, false)
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 15
-        sheet.apply(mc, OsmUtils.createPrimitive("way keyB=true"), 20, false)
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 15
-        sheet.apply(mc, OsmUtils.createPrimitive("way keyA=true keyB=true"), 20, false)
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("width") == 15
-    }
-
-    @Test
-    public void testTicket8071() throws Exception {
-        def sheet = new MapCSSStyleSource("" +
-                "*[rcn_ref], *[name] {text: concat(tag(rcn_ref), \" \", tag(name)); }")
-        sheet.loadStyleSource()
-        def mc = new MultiCascade()
-        sheet.apply(mc, OsmUtils.createPrimitive("way name=Foo"), 20, false)
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == " Foo"
-        sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15"), 20, false)
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == "15 "
-        sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15 name=Foo"), 20, false)
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == "15 Foo"
-
-        sheet = new MapCSSStyleSource("" +
-                "*[rcn_ref], *[name] {text: join(\" - \", tag(rcn_ref), tag(ref), tag(name)); }")
-        sheet.loadStyleSource()
-        sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15 ref=1.5 name=Foo"), 20, false)
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("text") == "15 - 1.5 - Foo"
-    }
-
-    @Test
-    public void testColorNameTicket9191() throws Exception {
-        def e = new Environment(null, new MultiCascade(), Environment.DEFAULT_LAYER, null)
-        getParser("{color: testcolour1#88DD22}").declaration().instructions.get(0).execute(e)
-        def expected = new Color(0x88DD22)
-        assert e.getCascade(Environment.DEFAULT_LAYER).get("color") == expected
-    }
-
-    @Test
-    public void testColorNameTicket9191Alpha() throws Exception {
-        def e = new Environment(null, new MultiCascade(), Environment.DEFAULT_LAYER, null)
-        getParser("{color: testcolour2#12345678}").declaration().instructions.get(0).execute(e)
-        def expected = new Color(0x12, 0x34, 0x56, 0x78)
-        assert e.getCascade(Environment.DEFAULT_LAYER).get("color") == expected
-    }
-
-    @Test
-    public void testColorParsing() throws Exception {
-        assert ColorHelper.html2color("#12345678") == new Color(0x12, 0x34, 0x56, 0x78)
-    }
-
-    @Test
-    public void testChildSelectorGreaterThanSignIsOptional() throws Exception {
-        assert getParser("relation[type=route] way[highway]").child_selector().toString() ==
-                getParser("relation[type=route] > way[highway]").child_selector().toString()
-    }
-
-    @Test
-    public void testSiblingSelector() throws Exception {
-        def s1 = (Selector.ChildOrParentSelector) getParser("*[a?][parent_tag(\"highway\")=\"unclassified\"] + *[b?]").child_selector()
-        def ds = new DataSet()
-        def n1 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1, 2))
-        n1.put("a", "true")
-        def n2 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1.1, 2.2))
-        n2.put("b", "true")
-        def w = new Way()
-        w.put("highway", "unclassified")
-        ds.addPrimitive(n1)
-        ds.addPrimitive(n2)
-        ds.addPrimitive(w)
-        w.addNode(n1)
-        w.addNode(n2)
-
-        def e = new Environment(n2)
-        assert s1.matches(e)
-        assert e.osm == n2
-        assert e.child == n1
-        assert e.parent == w
-        assert !s1.matches(new Environment(n1))
-        assert !s1.matches(new Environment(w))
-    }
-
-    @Test
-    public void testParentTags() throws Exception {
-        def ds = new DataSet()
-        def n = new org.openstreetmap.josm.data.osm.Node(new LatLon(1, 2))
-        n.put("foo", "bar")
-        def w1 = new Way()
-        w1.put("ref", "x10")
-        def w2 = new Way()
-        w2.put("ref", "x2")
-        def w3 = new Way()
-        ds.addPrimitive(n)
-        ds.addPrimitive(w1)
-        ds.addPrimitive(w2)
-        ds.addPrimitive(w3)
-        w1.addNode(n)
-        w2.addNode(n)
-        w3.addNode(n)
-
-        MapCSSStyleSource source = new MapCSSStyleSource("node[foo=bar] {refs: join_list(\";\", parent_tags(\"ref\"));}")
-        source.loadStyleSource()
-        assert source.rules.size() == 1
-        def e = new Environment(n, new MultiCascade(), Environment.DEFAULT_LAYER, null)
-        assert source.rules.get(0).selector.matches(e)
-        source.rules.get(0).declaration.execute(e)
-        assert e.getCascade(Environment.DEFAULT_LAYER).get("refs", null, String.class) == "x2;x10"
-    }
-
-    @Test
-    public void testSiblingSelectorInterpolation() throws Exception {
-        def s1 = (Selector.ChildOrParentSelector) getParser(
-                "*[tag(\"addr:housenumber\") > child_tag(\"addr:housenumber\")][regexp_test(\"even|odd\", parent_tag(\"addr:interpolation\"))]" +
-                        " + *[addr:housenumber]").child_selector()
-        def ds = new DataSet()
-        def n1 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1, 2))
-        n1.put("addr:housenumber", "10")
-        def n2 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1.1, 2.2))
-        n2.put("addr:housenumber", "100")
-        def n3 = new org.openstreetmap.josm.data.osm.Node(new LatLon(1.2, 2.3))
-        n3.put("addr:housenumber", "20")
-        def w = new Way()
-        w.put("addr:interpolation", "even")
-        ds.addPrimitive(n1)
-        ds.addPrimitive(n2)
-        ds.addPrimitive(n3)
-        ds.addPrimitive(w)
-        w.addNode(n1)
-        w.addNode(n2)
-        w.addNode(n3)
-
-        assert s1.right.matches(new Environment(n3))
-        assert s1.left.matches(new Environment(n2).withChild(n3).withParent(w))
-        assert s1.matches(new Environment(n3))
-        assert !s1.matches(new Environment(n1))
-        assert !s1.matches(new Environment(n2))
-        assert !s1.matches(new Environment(w))
-    }
-
-    @Test
-    public void testInvalidBaseSelector() throws Exception {
-        def css = new MapCSSStyleSource("invalid_base[key=value] {}")
-        css.loadStyleSource()
-        assert !css.getErrors().isEmpty()
-        assert css.getErrors().iterator().next().toString().contains("Unknown MapCSS base selector invalid_base")
-    }
-
-    @Test
-    public void testMinMaxFunctions() throws Exception {
-        def sheet = new MapCSSStyleSource("* {" +
-                "min_value: min(tag(x), tag(y), tag(z)); " +
-                "max_value: max(tag(x), tag(y), tag(z)); " +
-                "max_split: max(split(\";\", tag(widths))); " +
-                "}")
-        sheet.loadStyleSource()
-        def mc = new MultiCascade()
-
-        sheet.apply(mc, OsmUtils.createPrimitive("way x=4 y=6 z=8 u=100"), 20, false)
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", Float.NaN, Float.class) == 4.0f
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", Float.NaN, Float.class) == 8.0f
-
-        sheet.apply(mc, OsmUtils.createPrimitive("way x=4 y=6 widths=1;2;8;56;3;a"), 20, false)
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", -777f, Float.class) == 4
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", -777f, Float.class) == 6
-        assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_split", -777f, Float.class) == 56
-    }
-
-    @Test
-    public void testTicket12549() throws Exception {
-        def condition = getParser("[name =~ /^(?i)(?u)fóo\$/]").condition(Condition.Context.PRIMITIVE)
-        assert condition.applies(new Environment(OsmUtils.createPrimitive("way name=fóo")))
-        assert condition.applies(new Environment(OsmUtils.createPrimitive("way name=fÓo")))
-        condition = getParser("[name =~ /^(\\p{Lower})+\$/]").condition(Condition.Context.PRIMITIVE)
-        assert !condition.applies(new Environment(OsmUtils.createPrimitive("way name=fóo")))
-        condition = getParser("[name =~ /^(?U)(\\p{Lower})+\$/]").condition(Condition.Context.PRIMITIVE)
-        assert condition.applies(new Environment(OsmUtils.createPrimitive("way name=fóo")))
-        assert !condition.applies(new Environment(OsmUtils.createPrimitive("way name=fÓo")))
-    }
-}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.java	(revision 14064)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.java	(revision 14064)
@@ -0,0 +1,470 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.mapcss;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Color;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmUtils;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.mappaint.Environment;
+import org.openstreetmap.josm.gui.mappaint.MultiCascade;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.ClassCondition;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyCondition;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyMatchType;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.KeyValueCondition;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.Op;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.PseudoClassCondition;
+import org.openstreetmap.josm.gui.mappaint.mapcss.ConditionFactory.SimpleKeyValueCondition;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
+import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.tools.ColorHelper;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Unit tests of {@link MapCSSParser}.
+ */
+public class MapCSSParserTest {
+
+    protected static Environment getEnvironment(String key, String value) {
+        return new Environment(OsmUtils.createPrimitive("way " + key + "=" + value));
+    }
+
+    protected static MapCSSParser getParser(String stringToParse) {
+        return new MapCSSParser(new StringReader(stringToParse));
+    }
+
+    /**
+     * Setup rule
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().projection();
+
+    @Test
+    public void testKothicStylesheets() throws Exception {
+        new MapCSSParser(new URL("https://raw.githubusercontent.com/kothic/kothic/master/src/styles/default.mapcss").openStream(), "UTF-8");
+        new MapCSSParser(new URL("https://raw.githubusercontent.com/kothic/kothic/master/src/styles/mapink.mapcss").openStream(), "UTF-8");
+    }
+
+    @Test
+    public void testDeclarations() throws Exception {
+        getParser("{ opacity: 0.5; color: rgb(1.0, 0.0, 0.0); }").declaration();
+        getParser("{ set tag=value; }").declaration(); //set a tag
+        getParser("{ set tag; }").declaration(); // set a tag to 'yes'
+        getParser("{ opacity: eval(\"tag('population')/100000\"); }").declaration();
+        getParser("{ set width_in_metres=eval(\"tag('lanes')*3\"); }").declaration();
+    }
+
+    @Test
+    public void testClassCondition() throws Exception {
+        List<Condition> conditions = ((Selector.GeneralSelector) getParser("way[name=X].highway:closed").selector()).conds;
+        assertTrue(conditions.get(0) instanceof SimpleKeyValueCondition);
+        assertTrue(conditions.get(0).applies(getEnvironment("name", "X")));
+        assertTrue(conditions.get(1) instanceof ClassCondition);
+        assertTrue(conditions.get(2) instanceof PseudoClassCondition);
+        assertFalse(conditions.get(2).applies(getEnvironment("name", "X")));
+    }
+
+    @Test
+    public void testPseudoClassCondition() throws Exception {
+        Condition c1 = ((Selector.GeneralSelector) getParser("way!:area-style").selector()).conds.get(0);
+        Condition c2 = ((Selector.GeneralSelector) getParser("way!:areaStyle").selector()).conds.get(0);
+        Condition c3 = ((Selector.GeneralSelector) getParser("way!:area_style").selector()).conds.get(0);
+        assertEquals("!:areaStyle", c1.toString());
+        assertEquals("!:areaStyle", c2.toString());
+        assertEquals("!:areaStyle", c3.toString());
+    }
+
+    @Test
+    public void testClassMatching() throws Exception {
+        MapCSSStyleSource css = new MapCSSStyleSource(
+                "way[highway=footway] { set .path; color: #FF6644; width: 2; }\n" +
+                "way[highway=path]    { set path; color: brown; width: 2; }\n" +
+                "way[\"set\"=escape]  {  }\n" +
+                "way.path             { text:auto; text-color: green; text-position: line; text-offset: 5; }\n" +
+                "way!.path            { color: orange; }\n"
+        );
+        css.loadStyleSource();
+        assertTrue(css.getErrors().isEmpty());
+        MultiCascade mc1 = new MultiCascade();
+        css.apply(mc1, OsmUtils.createPrimitive("way highway=path"), 1, false);
+        assertEquals("green", mc1.getCascade("default").get("text-color", null, String.class));
+        assertEquals("brown", mc1.getCascade("default").get("color", null, String.class));
+        MultiCascade mc2 = new MultiCascade();
+        css.apply(mc2, OsmUtils.createPrimitive("way highway=residential"), 1, false);
+        assertEquals("orange", mc2.getCascade("default").get("color", null, String.class));
+        assertNull(mc2.getCascade("default").get("text-color", null, String.class));
+        MultiCascade mc3 = new MultiCascade();
+        css.apply(mc3, OsmUtils.createPrimitive("way highway=footway"), 1, false);
+        assertEquals(ColorHelper.html2color("#FF6644"), mc3.getCascade("default").get("color", null, Color.class));
+    }
+
+    @Test
+    public void testEqualCondition() throws Exception {
+        Condition condition = getParser("[surface=paved]").condition(Condition.Context.PRIMITIVE);
+        assertTrue(condition instanceof SimpleKeyValueCondition);
+        assertEquals("surface", ((SimpleKeyValueCondition) condition).k);
+        assertEquals("paved", ((SimpleKeyValueCondition) condition).v);
+        assertTrue(condition.applies(getEnvironment("surface", "paved")));
+        assertFalse(condition.applies(getEnvironment("surface", "unpaved")));
+    }
+
+    @Test
+    public void testNotEqualCondition() throws Exception {
+        KeyValueCondition condition = (KeyValueCondition) getParser("[surface!=paved]").condition(Condition.Context.PRIMITIVE);
+        assertEquals(Op.NEQ, condition.op);
+        assertFalse(condition.applies(getEnvironment("surface", "paved")));
+        assertTrue(condition.applies(getEnvironment("surface", "unpaved")));
+    }
+
+    @Test
+    public void testRegexCondition() throws Exception {
+        KeyValueCondition condition = (KeyValueCondition) getParser("[surface=~/paved|unpaved/]").condition(Condition.Context.PRIMITIVE);
+        assertEquals(Op.REGEX, condition.op);
+        assertTrue(condition.applies(getEnvironment("surface", "unpaved")));
+        assertFalse(condition.applies(getEnvironment("surface", "grass")));
+    }
+
+    @Test
+    public void testRegexConditionParenthesis() throws Exception {
+        KeyValueCondition condition = (KeyValueCondition) getParser("[name =~ /^\\(foo\\)/]").condition(Condition.Context.PRIMITIVE);
+        assertTrue(condition.applies(getEnvironment("name", "(foo)")));
+        assertFalse(condition.applies(getEnvironment("name", "foo")));
+        assertFalse(condition.applies(getEnvironment("name", "((foo))")));
+    }
+
+    @Test
+    public void testNegatedRegexCondition() throws Exception {
+        KeyValueCondition condition = (KeyValueCondition) getParser("[surface!~/paved|unpaved/]").condition(Condition.Context.PRIMITIVE);
+        assertEquals(Op.NREGEX, condition.op);
+        assertFalse(condition.applies(getEnvironment("surface", "unpaved")));
+        assertTrue(condition.applies(getEnvironment("surface", "grass")));
+    }
+
+    @Test
+    public void testBeginsEndsWithCondition() throws Exception {
+        KeyValueCondition condition = (KeyValueCondition) getParser("[foo ^= bar]").condition(Condition.Context.PRIMITIVE);
+        assertEquals(Op.BEGINS_WITH, condition.op);
+        assertTrue(condition.applies(getEnvironment("foo", "bar123")));
+        assertFalse(condition.applies(getEnvironment("foo", "123bar")));
+        assertFalse(condition.applies(getEnvironment("foo", "123bar123")));
+        condition = (KeyValueCondition) getParser("[foo $= bar]").condition(Condition.Context.PRIMITIVE);
+        assertEquals(Op.ENDS_WITH, condition.op);
+        assertFalse(condition.applies(getEnvironment("foo", "bar123")));
+        assertTrue(condition.applies(getEnvironment("foo", "123bar")));
+        assertFalse(condition.applies(getEnvironment("foo", "123bar123")));
+    }
+
+    @Test
+    public void testOneOfCondition() throws Exception {
+        Condition condition = getParser("[vending~=stamps]").condition(Condition.Context.PRIMITIVE);
+        assertTrue(condition.applies(getEnvironment("vending", "stamps")));
+        assertTrue(condition.applies(getEnvironment("vending", "bar;stamps;foo")));
+        assertFalse(condition.applies(getEnvironment("vending", "every;thing;else")));
+        assertFalse(condition.applies(getEnvironment("vending", "or_nothing")));
+    }
+
+    @Test
+    public void testStandardKeyCondition() throws Exception {
+        KeyCondition c1 = (KeyCondition) getParser("[ highway ]").condition(Condition.Context.PRIMITIVE);
+        assertEquals(KeyMatchType.EQ, c1.matchType);
+        assertTrue(c1.applies(getEnvironment("highway", "unclassified")));
+        assertFalse(c1.applies(getEnvironment("railway", "rail")));
+        KeyCondition c2 = (KeyCondition) getParser("[\"/slash/\"]").condition(Condition.Context.PRIMITIVE);
+        assertEquals(KeyMatchType.EQ, c2.matchType);
+        assertTrue(c2.applies(getEnvironment("/slash/", "yes")));
+        assertFalse(c2.applies(getEnvironment("\"slash\"", "no")));
+    }
+
+    @Test
+    public void testYesNoKeyCondition() throws Exception {
+        KeyCondition c1 = (KeyCondition) getParser("[oneway?]").condition(Condition.Context.PRIMITIVE);
+        KeyCondition c2 = (KeyCondition) getParser("[oneway?!]").condition(Condition.Context.PRIMITIVE);
+        KeyCondition c3 = (KeyCondition) getParser("[!oneway?]").condition(Condition.Context.PRIMITIVE);
+        KeyCondition c4 = (KeyCondition) getParser("[!oneway?!]").condition(Condition.Context.PRIMITIVE);
+        Environment yes = getEnvironment("oneway", "yes");
+        Environment no = getEnvironment("oneway", "no");
+        Environment none = getEnvironment("no-oneway", "foo");
+        assertTrue(c1.applies(yes));
+        assertFalse(c1.applies(no));
+        assertFalse(c1.applies(none));
+        assertFalse(c2.applies(yes));
+        assertTrue(c2.applies(no));
+        assertFalse(c2.applies(none));
+        assertFalse(c3.applies(yes));
+        assertTrue(c3.applies(no));
+        assertTrue(c3.applies(none));
+        assertTrue(c4.applies(yes));
+        assertFalse(c4.applies(no));
+        assertTrue(c4.applies(none));
+    }
+
+    @Test
+    public void testRegexKeyCondition() throws Exception {
+        KeyCondition c1 = (KeyCondition) getParser("[/.*:(backward|forward)$/]").condition(Condition.Context.PRIMITIVE);
+        assertEquals(KeyMatchType.REGEX, c1.matchType);
+        assertFalse(c1.applies(getEnvironment("lanes", "3")));
+        assertTrue(c1.applies(getEnvironment("lanes:forward", "3")));
+        assertTrue(c1.applies(getEnvironment("lanes:backward", "3")));
+        assertFalse(c1.applies(getEnvironment("lanes:foobar", "3")));
+    }
+
+    @Test
+    public void testNRegexKeyConditionSelector() throws Exception {
+        Selector s1 = getParser("*[sport][tourism != hotel]").selector();
+        assertTrue(s1.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar"))));
+        assertFalse(s1.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar tourism=hotel"))));
+        Selector s2 = getParser("*[sport][tourism != hotel][leisure !~ /^(sports_centre|stadium|)$/]").selector();
+        assertTrue(s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar"))));
+        assertFalse(s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar tourism=hotel"))));
+        assertFalse(s2.matches(new Environment(OsmUtils.createPrimitive("node sport=foobar leisure=stadium"))));
+    }
+
+    @Test
+    public void testKeyKeyCondition() throws Exception {
+        KeyValueCondition c1 = (KeyValueCondition) getParser("[foo = *bar]").condition(Condition.Context.PRIMITIVE);
+        Way w1 = new Way();
+        w1.put("foo", "123");
+        w1.put("bar", "456");
+        assertFalse(c1.applies(new Environment(w1)));
+        w1.put("bar", "123");
+        assertTrue(c1.applies(new Environment(w1)));
+        KeyValueCondition c2 = (KeyValueCondition) getParser("[foo =~ */bar/]").condition(Condition.Context.PRIMITIVE);
+        Way w2 = new Way(w1);
+        w2.put("bar", "[0-9]{3}");
+        assertTrue(c2.applies(new Environment(w2)));
+        w2.put("bar", "[0-9]");
+        assertTrue(c2.applies(new Environment(w2)));
+        w2.put("bar", "^[0-9]$");
+        assertFalse(c2.applies(new Environment(w2)));
+    }
+
+    @Test
+    public void testParentTag() throws Exception {
+        Selector c1 = getParser("way[foo] > node[tag(\"foo\")=parent_tag(\"foo\")] {}").child_selector();
+        DataSet ds = new DataSet();
+        Way w1 = new Way();
+        Way w2 = new Way();
+        Node n1 = new Node(new LatLon(1, 1));
+        Node n2 = new Node(new LatLon(2, 2));
+        w1.put("foo", "123");
+        w2.put("foo", "123");
+        n1.put("foo", "123");
+        n2.put("foo", "0");
+        ds.addPrimitive(w1);
+        ds.addPrimitive(n1);
+        ds.addPrimitive(n2);
+        w1.addNode(n1);
+        w2.addNode(n2);
+        assertTrue(c1.matches(new Environment(n1)));
+        assertFalse(c1.matches(new Environment(n2)));
+        assertFalse(c1.matches(new Environment(w1)));
+        assertFalse(c1.matches(new Environment(w2)));
+        n1.put("foo", "0");
+        assertFalse(c1.matches(new Environment(n1)));
+        n1.put("foo", "123");
+        assertTrue(c1.matches(new Environment(n1)));
+    }
+
+    @Test
+    public void testTicket8568() throws Exception {
+        MapCSSStyleSource sheet = new MapCSSStyleSource(
+                "way { width: 5; }\n" +
+                "way[keyA], way[keyB] { width: eval(prop(width)+10); }");
+        sheet.loadStyleSource();
+        MultiCascade mc = new MultiCascade();
+        sheet.apply(mc, OsmUtils.createPrimitive("way foo=bar"), 20, false);
+        assertEquals(Float.valueOf(5f), mc.getCascade(Environment.DEFAULT_LAYER).get("width"));
+        sheet.apply(mc, OsmUtils.createPrimitive("way keyA=true"), 20, false);
+        assertEquals(Float.valueOf(15f), mc.getCascade(Environment.DEFAULT_LAYER).get("width"));
+        sheet.apply(mc, OsmUtils.createPrimitive("way keyB=true"), 20, false);
+        assertEquals(Float.valueOf(15f), mc.getCascade(Environment.DEFAULT_LAYER).get("width"));
+        sheet.apply(mc, OsmUtils.createPrimitive("way keyA=true keyB=true"), 20, false);
+        assertEquals(Float.valueOf(15f), mc.getCascade(Environment.DEFAULT_LAYER).get("width"));
+    }
+
+    @Test
+    public void testTicket8071() throws Exception {
+        MapCSSStyleSource sheet = new MapCSSStyleSource(
+                "*[rcn_ref], *[name] {text: concat(tag(rcn_ref), \" \", tag(name)); }");
+        sheet.loadStyleSource();
+        MultiCascade mc = new MultiCascade();
+        sheet.apply(mc, OsmUtils.createPrimitive("way name=Foo"), 20, false);
+        assertEquals(" Foo", mc.getCascade(Environment.DEFAULT_LAYER).get("text"));
+        sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15"), 20, false);
+        assertEquals("15 ", mc.getCascade(Environment.DEFAULT_LAYER).get("text"));
+        sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15 name=Foo"), 20, false);
+        assertEquals("15 Foo", mc.getCascade(Environment.DEFAULT_LAYER).get("text"));
+
+        sheet = new MapCSSStyleSource("" +
+                "*[rcn_ref], *[name] {text: join(\" - \", tag(rcn_ref), tag(ref), tag(name)); }");
+        sheet.loadStyleSource();
+        sheet.apply(mc, OsmUtils.createPrimitive("way rcn_ref=15 ref=1.5 name=Foo"), 20, false);
+        assertEquals("15 - 1.5 - Foo", mc.getCascade(Environment.DEFAULT_LAYER).get("text"));
+    }
+
+    @Test
+    public void testColorNameTicket9191() throws Exception {
+        Environment e = new Environment(null, new MultiCascade(), Environment.DEFAULT_LAYER, null);
+        getParser("{color: testcolour1#88DD22}").declaration().instructions.get(0).execute(e);
+        Color expected = new Color(0x88DD22);
+        assertEquals(expected, e.getCascade(Environment.DEFAULT_LAYER).get("color"));
+    }
+
+    @Test
+    public void testColorNameTicket9191Alpha() throws Exception {
+        Environment e = new Environment(null, new MultiCascade(), Environment.DEFAULT_LAYER, null);
+        getParser("{color: testcolour2#12345678}").declaration().instructions.get(0).execute(e);
+        Color expected = new Color(0x12, 0x34, 0x56, 0x78);
+        assertEquals(expected, e.getCascade(Environment.DEFAULT_LAYER).get("color"));
+    }
+
+    @Test
+    public void testColorParsing() throws Exception {
+        assertEquals(new Color(0x12, 0x34, 0x56, 0x78), ColorHelper.html2color("#12345678"));
+    }
+
+    @Test
+    public void testChildSelectorGreaterThanSignIsOptional() throws Exception {
+        assertEquals(
+                getParser("relation[type=route] way[highway]").child_selector().toString(),
+                getParser("relation[type=route] > way[highway]").child_selector().toString());
+    }
+
+    @Test
+    public void testSiblingSelector() throws Exception {
+        ChildOrParentSelector s1 = (Selector.ChildOrParentSelector) getParser(
+                "*[a?][parent_tag(\"highway\")=\"unclassified\"] + *[b?]").child_selector();
+        DataSet ds = new DataSet();
+        Node n1 = new Node(new LatLon(1, 2));
+        n1.put("a", "true");
+        Node n2 = new Node(new LatLon(1.1, 2.2));
+        n2.put("b", "true");
+        Way w = new Way();
+        w.put("highway", "unclassified");
+        ds.addPrimitive(n1);
+        ds.addPrimitive(n2);
+        ds.addPrimitive(w);
+        w.addNode(n1);
+        w.addNode(n2);
+
+        Environment e = new Environment(n2);
+        assertTrue(s1.matches(e));
+        assertEquals(n2, e.osm);
+        assertEquals(n1, e.child);
+        assertEquals(w, e.parent);
+        assertFalse(s1.matches(new Environment(n1)));
+        assertFalse(s1.matches(new Environment(w)));
+    }
+
+    @Test
+    public void testParentTags() throws Exception {
+        DataSet ds = new DataSet();
+        Node n = new Node(new LatLon(1, 2));
+        n.put("foo", "bar");
+        Way w1 = new Way();
+        w1.put("ref", "x10");
+        Way w2 = new Way();
+        w2.put("ref", "x2");
+        Way w3 = new Way();
+        ds.addPrimitive(n);
+        ds.addPrimitive(w1);
+        ds.addPrimitive(w2);
+        ds.addPrimitive(w3);
+        w1.addNode(n);
+        w2.addNode(n);
+        w3.addNode(n);
+
+        MapCSSStyleSource source = new MapCSSStyleSource("node[foo=bar] {refs: join_list(\";\", parent_tags(\"ref\"));}");
+        source.loadStyleSource();
+        assertEquals(1, source.rules.size());
+        Environment e = new Environment(n, new MultiCascade(), Environment.DEFAULT_LAYER, null);
+        assertTrue(source.rules.get(0).selector.matches(e));
+        source.rules.get(0).declaration.execute(e);
+        assertEquals("x2;x10", e.getCascade(Environment.DEFAULT_LAYER).get("refs", null, String.class));
+    }
+
+    @Test
+    public void testSiblingSelectorInterpolation() throws Exception {
+        ChildOrParentSelector s1 = (Selector.ChildOrParentSelector) getParser(
+                "*[tag(\"addr:housenumber\") > child_tag(\"addr:housenumber\")][regexp_test(\"even|odd\", parent_tag(\"addr:interpolation\"))]" +
+                        " + *[addr:housenumber]").child_selector();
+        DataSet ds = new DataSet();
+        Node n1 = new Node(new LatLon(1, 2));
+        n1.put("addr:housenumber", "10");
+        Node n2 = new Node(new LatLon(1.1, 2.2));
+        n2.put("addr:housenumber", "100");
+        Node n3 = new Node(new LatLon(1.2, 2.3));
+        n3.put("addr:housenumber", "20");
+        Way w = new Way();
+        w.put("addr:interpolation", "even");
+        ds.addPrimitive(n1);
+        ds.addPrimitive(n2);
+        ds.addPrimitive(n3);
+        ds.addPrimitive(w);
+        w.addNode(n1);
+        w.addNode(n2);
+        w.addNode(n3);
+
+        assertTrue(s1.right.matches(new Environment(n3)));
+        assertTrue(s1.left.matches(new Environment(n2).withChild(n3).withParent(w)));
+        assertTrue(s1.matches(new Environment(n3)));
+        assertFalse(s1.matches(new Environment(n1)));
+        assertFalse(s1.matches(new Environment(n2)));
+        assertFalse(s1.matches(new Environment(w)));
+    }
+
+    @Test
+    public void testInvalidBaseSelector() throws Exception {
+        MapCSSStyleSource css = new MapCSSStyleSource("invalid_base[key=value] {}");
+        css.loadStyleSource();
+        assertFalse(css.getErrors().isEmpty());
+        assertTrue(css.getErrors().iterator().next().toString().contains("Unknown MapCSS base selector invalid_base"));
+    }
+
+    @Test
+    public void testMinMaxFunctions() throws Exception {
+        MapCSSStyleSource sheet = new MapCSSStyleSource("* {" +
+                "min_value: min(tag(x), tag(y), tag(z)); " +
+                "max_value: max(tag(x), tag(y), tag(z)); " +
+                "max_split: max(split(\";\", tag(widths))); " +
+                "}");
+        sheet.loadStyleSource();
+        MultiCascade mc = new MultiCascade();
+
+        sheet.apply(mc, OsmUtils.createPrimitive("way x=4 y=6 z=8 u=100"), 20, false);
+        assertEquals(Float.valueOf(4.0f), mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", Float.NaN, Float.class));
+        assertEquals(Float.valueOf(8.0f), mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", Float.NaN, Float.class));
+
+        sheet.apply(mc, OsmUtils.createPrimitive("way x=4 y=6 widths=1;2;8;56;3;a"), 20, false);
+        assertEquals(Float.valueOf(4f), mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", -777f, Float.class));
+        assertEquals(Float.valueOf(6f), mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", -777f, Float.class));
+        assertEquals(Float.valueOf(56f), mc.getCascade(Environment.DEFAULT_LAYER).get("max_split", -777f, Float.class));
+    }
+
+    @Test
+    public void testTicket12549() throws Exception {
+        Condition condition = getParser("[name =~ /^(?i)(?u)fóo$/]").condition(Condition.Context.PRIMITIVE);
+        assertTrue(condition.applies(new Environment(OsmUtils.createPrimitive("way name=fóo"))));
+        assertTrue(condition.applies(new Environment(OsmUtils.createPrimitive("way name=fÓo"))));
+        condition = getParser("[name =~ /^(\\p{Lower})+$/]").condition(Condition.Context.PRIMITIVE);
+        assertFalse(condition.applies(new Environment(OsmUtils.createPrimitive("way name=fóo"))));
+        condition = getParser("[name =~ /^(?U)(\\p{Lower})+$/]").condition(Condition.Context.PRIMITIVE);
+        assertTrue(condition.applies(new Environment(OsmUtils.createPrimitive("way name=fóo"))));
+        assertFalse(condition.applies(new Environment(OsmUtils.createPrimitive("way name=fÓo"))));
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.groovy	(revision 14062)
+++ 	(revision )
@@ -1,58 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.mappaint.mapcss;
-
-import static org.junit.Assert.*
-
-import org.junit.*
-import org.openstreetmap.josm.JOSMFixture;
-
-
-class ParsingLinkSelectorTest {
-
-    @BeforeClass
-    public static void createJOSMFixture(){
-        JOSMFixture.createUnitTestFixture().init()
-    }
-
-    @Test
-    public void parseEmptyChildSelector() {
-        def css = """
-           relation > way {}
-        """
-        MapCSSStyleSource source = new MapCSSStyleSource(css)
-        source.loadStyleSource()
-        assert source.rules.size() == 1
-    }
-
-    @Test
-    public void parseEmptyParentSelector() {
-        def css = """
-           way < relation {}
-        """
-        MapCSSStyleSource source = new MapCSSStyleSource(css)
-        source.loadStyleSource()
-        assert source.rules.size() == 1
-    }
-
-
-    @Test
-    public void parseChildSelectorWithKeyValueCondition() {
-        def css = """
-           relation >[role="my_role"] way {}
-        """
-        MapCSSStyleSource source = new MapCSSStyleSource(css)
-        source.loadStyleSource()
-        assert source.rules.size() == 1
-    }
-
-    @Test
-    public void parseChildSelectorWithKeyCondition() {
-        def css = """
-           relation >["my_role"] way{}
-        """
-        MapCSSStyleSource source = new MapCSSStyleSource(css)
-        source.loadStyleSource()
-        assert source.rules.size() == 1
-    }
-}
-
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.java	(revision 14064)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.java	(revision 14064)
@@ -0,0 +1,55 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.mapcss;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Unit tests of {@code ParsingLinkSelector}.
+ */
+public class ParsingLinkSelectorTest {
+
+    /**
+     * Setup rule
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules().projection();
+
+    @Test
+    public void parseEmptyChildSelector() {
+        String css = "relation > way {}";
+        MapCSSStyleSource source = new MapCSSStyleSource(css);
+        source.loadStyleSource();
+        assertEquals(1, source.rules.size());
+    }
+
+    @Test
+    public void parseEmptyParentSelector() {
+        String css = "way < relation {}";
+        MapCSSStyleSource source = new MapCSSStyleSource(css);
+        source.loadStyleSource();
+        assertEquals(1, source.rules.size());
+    }
+
+    @Test
+    public void parseChildSelectorWithKeyValueCondition() {
+        String css = "relation >[role=\"my_role\"] way {}";
+        MapCSSStyleSource source = new MapCSSStyleSource(css);
+        source.loadStyleSource();
+        assertEquals(1, source.rules.size());
+    }
+
+    @Test
+    public void parseChildSelectorWithKeyCondition() {
+        String css = "relation >[\"my_role\"] way{}";
+        MapCSSStyleSource source = new MapCSSStyleSource(css);
+        source.loadStyleSource();
+        assertEquals(1, source.rules.size());
+    }
+}
