Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/AllMappaintTests.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/AllMappaintTests.groovy	(revision 3991)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/AllMappaintTests.groovy	(revision 4069)
@@ -2,13 +2,16 @@
 package org.openstreetmap.josm.gui.mappaint
 
-import junit.framework.TestCase;
+import junit.framework.TestCase
 
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import org.junit.runner.RunWith
+import org.junit.runners.Suite
+import org.openstreetmap.josm.gui.mappaint.mapcss.AllMapCSSTests
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses([
     LabelCompositionStrategyTest.class,
-    MapCSSWithExtendedTextDirectivesTest.class
+    MapCSSWithExtendedTextDirectivesTest.class,
+    AllMapCSSTests.class
+    
 ])
 public class AllMappaintTests extends TestCase{}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/MapCSSWithExtendedTextDirectivesTest.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/MapCSSWithExtendedTextDirectivesTest.groovy	(revision 3991)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/MapCSSWithExtendedTextDirectivesTest.groovy	(revision 4069)
@@ -2,11 +2,10 @@
 package org.openstreetmap.josm.gui.mappaint
 
-import java.awt.Color;
+import java.awt.Color
 
-import org.junit.*;
-import org.openstreetmap.josm.fixtures.JOSMFixture 
-import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.DeriveLabelFromNameTagsCompositionStrategy 
-import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.StaticLabelCompositionStrategy 
-import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.TagLookupCompositionStrategy 
+import org.junit.*
+import org.openstreetmap.josm.fixtures.JOSMFixture
+import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.DeriveLabelFromNameTagsCompositionStrategy
+import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.TagLookupCompositionStrategy
 class MapCSSWithExtendedTextDirectivesTest {
     
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/AllMapCSSTests.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/AllMapCSSTests.groovy	(revision 4069)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/AllMapCSSTests.groovy	(revision 4069)
@@ -0,0 +1,17 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.mapcss
+
+import junit.framework.TestCase
+
+import org.junit.runner.RunWith
+import org.junit.runners.Suite
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses([
+    KeyValueConditionTest.class,
+    ParsingLinkSelectorTest.class,
+    KeyConditionTest.class,
+    ChildOrParentSelectorTest
+])
+public class AllMapCSSTests extends TestCase{}
+
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ChildOrParentSelectorTest.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ChildOrParentSelectorTest.groovy	(revision 4069)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ChildOrParentSelectorTest.groovy	(revision 4069)
@@ -0,0 +1,177 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.mapcss;
+
+import static org.junit.Assert.*
+
+import java.util.logging.Logger
+
+import org.junit.*
+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.data.osm.Way
+import org.openstreetmap.josm.fixtures.JOSMFixture
+import org.openstreetmap.josm.gui.mappaint.Environment
+import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector
+
+class ChildOrParentSelectorTest {
+    static private Logger logger = Logger.getLogger(ChildOrParentSelectorTest.class.getName());
+    
+    def shouldFail = new GroovyTestCase().&shouldFail
+    
+    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(new LatLon(0,0))
+        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
+         assert source.rules[0].selectors.size() == 1
+         return source.rules[0].selectors[0]
+    }
+    
+    @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.parentSelector
+        
+    }
+    @Test
+    public void matches_5() {
+        def css = """
+           way <[role != "my_role"] relation {}
+        """
+        ChildOrParentSelector selector = parse(css)   
+        assert selector.parentSelector     
+        
+        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().withPrimitive(r)
+        assert selector.matches(e)
+    }
+    
+    @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().withPrimitive(w1)
+        assert !selector.matches(e)
+        
+        e = new Environment().withPrimitive(w2)
+        assert !selector.matches(e)
+        
+        e = new Environment().withPrimitive(w3)
+        assert selector.matches(e)
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.groovy	(revision 4069)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyConditionTest.groovy	(revision 4069)
@@ -0,0 +1,102 @@
+// 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.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.fixtures.JOSMFixture
+import org.openstreetmap.josm.gui.mappaint.Environment
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context
+
+class KeyConditionTest {
+
+    def shouldFail = new GroovyTestCase().&shouldFail
+    
+    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(new LatLon(0,0))
+        ds.addPrimitive(n)
+        return n
+    }
+    
+    @Test
+    public void create() {
+        
+        // ["a label"]
+        Condition c = Condition.create("a key", false, false, Context.PRIMITIVE)
+        // ["a label"?]
+        c = Condition.create("a key", false, true, Context.PRIMITIVE)
+        // [!"a label"]
+        c = Condition.create("a key", true, false, Context.PRIMITIVE)
+        // [!"a label"?]
+        c = Condition.create("a key", true, true, Context.PRIMITIVE)
+       
+        // ["a label"]
+        c = Condition.create("a key", false, false, Context.LINK)
+        // [!"a label"]
+        c = Condition.create("a key", true, false, Context.LINK)
+        
+        shouldFail(MapCSSException) {
+            // ["a label"?]
+           c = Condition.create("a key", false, true, Context.LINK)
+        }
+        
+        shouldFail(MapCSSException) {
+            // [!"a label"?]
+            c = Condition.create("a key", true, 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().withPrimitive(n).withParent(r).withIndex(0).withLinkContext()
+        
+        Condition cond = Condition.create("my_role", false, false, Context.LINK)
+        assert cond.applies(e)        
+        
+        cond = Condition.create("my_role", true, false, 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().withPrimitive(n).withParent(r).withIndex(0).withLinkContext()
+        
+        Condition cond = Condition.create("another_role", false, false, Context.LINK)
+        assert !cond.applies(e)
+        
+        cond = Condition.create("another_role", true, false, Context.LINK)
+        assert 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 4069)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/KeyValueConditionTest.groovy	(revision 4069)
@@ -0,0 +1,91 @@
+// 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.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.fixtures.JOSMFixture
+import org.openstreetmap.josm.gui.mappaint.Environment
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Context
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Op
+
+
+class KeyValueConditionTest {
+
+    def shouldFail = new GroovyTestCase().&shouldFail
+    
+    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(new LatLon(0,0))
+        ds.addPrimitive(n)
+        return n
+    }
+    
+    @Test
+    public void create() {
+        Condition c = Condition.create("a key", "a value", Op.EQ, Context.PRIMITIVE)
+        
+        c = Condition.create("role", "a role", Op.EQ, Context.LINK)
+        c = Condition.create("RoLe", "a role", Op.EQ, Context.LINK)
+        
+        shouldFail(MapCSSException) {
+            c = Condition.create("an arbitry tag", "a role", Op.EQ, 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().withPrimitive(n).withParent(r).withLinkContext().withIndex(0)
+        
+        Condition cond = new Condition.RoleCondition("my_role", Op.EQ)
+        assert cond.applies(e)        
+        
+        cond = new Condition.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().withPrimitive(n).withParent(r).withIndex(0).withLinkContext()
+        
+        Condition cond = Condition.create("role", "my_role", Op.NEQ, Context.LINK)
+        assert !cond.applies(e)
+        
+        cond = Condition.create("role", "another_role", Op.NEQ, Context.LINK)
+        assert cond.applies(e)
+    }
+    
+    
+    
+}
Index: trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.groovy	(revision 4069)
+++ trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ParsingLinkSelectorTest.groovy	(revision 4069)
@@ -0,0 +1,57 @@
+// 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.fixtures.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
+    }
+}
