Updated dominance with type and label serialization.

Change-Id: I685ae7f8723ee6c87531665a035cd53b43de257a
diff --git a/src/main/antlr/annis/AqlParser.g4 b/src/main/antlr/annis/AqlParser.g4
index a55abcc..f510979 100644
--- a/src/main/antlr/annis/AqlParser.g4
+++ b/src/main/antlr/annis/AqlParser.g4
@@ -58,15 +58,14 @@
 ;
 
 edgeType
-:	((foundry '/')? layer eqOperator)? textSpec
-;
+: ID;
 
 edgeAnno
 :	((foundry '/')? (layer COLON)? key eqOperator)? textSpec
 ;
 
 edgeSpec
-: BRACKET_OPEN (edgeAnno WS*)+ BRACKET_CLOSE
+: BRACKET_OPEN edgeAnno BRACKET_CLOSE
 ;
 
 refOrNode
@@ -80,22 +79,16 @@
 | PRECEDENCE (layer COMMA?)? rangeSpec #RangePrecedence
 ;
 
-// EM: dominance may have a type. Is qName appropriate for the dominance type?
 dominance
-: DOMINANCE (qName)? (LEFT_CHILD | RIGHT_CHILD)? (anno=edgeSpec)? # DirectDominance
-| DOMINANCE (qName)? STAR # IndirectDominance
-| DOMINANCE (qName)? rangeSpec? # RangeDominance
+: DOMINANCE (edgeType)? (LEFT_CHILD | RIGHT_CHILD)? (anno=edgeSpec)? # DirectDominance
+| DOMINANCE (edgeType)? STAR # IndirectDominance
+| DOMINANCE (edgeType)? rangeSpec? # RangeDominance
 ;
 
-// EM: qName is edgeType
 pointing
-: POINTING (qName | edgeType) (anno=edgeSpec)? # DirectPointing
-| POINTING (qName | edgeType) (anno=edgeSpec)? STAR # IndirectPointing
-| POINTING (qName | edgeType) (anno=edgeSpec)? COMMA? rangeSpec # RangePointing
-
-//: POINTING qName (anno=edgeSpec)? # DirectPointing
-//| POINTING qName (anno=edgeSpec)? STAR # IndirectPointing
-//| POINTING qName (anno=edgeSpec)? COMMA? rangeSpec # RangePointing
+: POINTING qName (anno=edgeSpec)? # DirectPointing
+| POINTING qName (anno=edgeSpec)? STAR # IndirectPointing
+| POINTING qName (anno=edgeSpec)? COMMA? rangeSpec # RangePointing
 ;
 
 spanrelation
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/AnnisQueryProcessor.java b/src/main/java/de/ids_mannheim/korap/query/serialize/AnnisQueryProcessor.java
index f076255..0573fd4 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/AnnisQueryProcessor.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/AnnisQueryProcessor.java
@@ -4,11 +4,14 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Set;
 
+import org.antlr.v4.parse.ANTLRParser.throwsSpec_return;
 import org.antlr.v4.runtime.ANTLRInputStream;
 import org.antlr.v4.runtime.BailErrorStrategy;
 import org.antlr.v4.runtime.CharStream;
@@ -20,11 +23,13 @@
 import org.slf4j.LoggerFactory;
 
 import de.ids_mannheim.korap.query.object.KoralFrame;
+import de.ids_mannheim.korap.query.object.KoralMatchOperator;
 import de.ids_mannheim.korap.query.object.KoralOperation;
 import de.ids_mannheim.korap.query.object.KoralTermGroupRelation;
 import de.ids_mannheim.korap.query.parse.annis.AqlLexer;
 import de.ids_mannheim.korap.query.parse.annis.AqlParser;
 import de.ids_mannheim.korap.query.serialize.util.Antlr4DescriptiveErrorListener;
+import de.ids_mannheim.korap.query.serialize.util.KoralException;
 import de.ids_mannheim.korap.query.serialize.util.KoralObjectGenerator;
 import de.ids_mannheim.korap.query.serialize.util.StatusCodes;
 
@@ -685,6 +690,7 @@
             else {
                 Map<String, Object> operatorGroup = parseOperatorNode(
                         node.getChild(i).getChild(0));
+                // EM: change group type to enum KoralOperation
                 String groupType;
                 try {
                     groupType = (String) operatorGroup.get("groupType");
@@ -698,22 +704,31 @@
                     group = KoralObjectGenerator
                             .makeGroup(KoralOperation.RELATION);
                     Map<String, Object> relation = new HashMap<String, Object>();
-                    putAllButGroupType(relation, operatorGroup);
+                    putAllBut(relation, operatorGroup, "groupType");
                     group.put("relType", relation);
                 }
                 else if (groupType.equals("sequence")) {
                     group = KoralObjectGenerator
                             .makeGroup(KoralOperation.SEQUENCE);
-                    putAllButGroupType(group, operatorGroup);
+                    putAllBut(group, operatorGroup, "groupType");
                 }
                 else if (groupType.equals("hierarchy")) {
                     group = KoralObjectGenerator
                             .makeGroup(KoralOperation.HIERARCHY);
-                    putAllButGroupType(group, operatorGroup);
+                    if (operatorGroup.containsKey("edgeValue")) {
+                        String edgeValue = (String) operatorGroup
+                                .get("edgeValue");
+                        inheritFoundryAndLayer(edgeValue, operand1, operand2);
+                    }
+                    if (operatorGroup.containsKey("boundary")) {
+                        checkBoundary((Map<String, Object>) operatorGroup
+                                .get("boundary"), operand1, operand2);
+                    }
+                    putAllBut(group, operatorGroup, "groupType", "edgeValue");
                 }
                 else if (groupType.equals("position")) {
                     group = new HashMap<String, Object>();
-                    putAllButGroupType(group, operatorGroup);
+                    putAllBut(group, operatorGroup, "groupType");
                 }
 
                 // Get operands list before possible re-assignment of 'group'
@@ -813,6 +828,104 @@
     }
 
 
+    private void checkBoundary (Map<String, Object> boundary,
+            Map<String, Object> operand1, Map<String, Object> operand2) {
+
+        boolean isDirect = true;
+        if (boundary.containsKey("min")) {
+            if ((int) boundary.get("min") != 1) {
+                isDirect = false;
+            }
+        }
+        if (isDirect && boundary.containsKey("max")) {
+            if ((int) boundary.get("max") != 1) {
+                isDirect = false;
+            }
+        }
+
+        if (!isDirect) {
+
+            String layer1 = searchMap(operand1, "layer");
+            String layer2 = searchMap(operand2, "layer");
+
+            if (layer1 != null && layer2 != null && !layer1.equals(layer2)) {
+                addError(StatusCodes.INCOMPATIBLE_OPERATOR_AND_OPERAND,
+                        "Indirect dominance between operands of different layers is not possible.");
+                return;
+            }
+
+            String foundry1 = searchMap(operand1, "foundry");
+            String foundry2 = searchMap(operand2, "foundry");
+
+            if (foundry1 != null && foundry2 != null
+                    && !foundry1.equals(foundry2)) {
+                addError(StatusCodes.INCOMPATIBLE_OPERATOR_AND_OPERAND,
+                        "Indirect dominance between operands of different foundries is not possible.");
+            }
+        }
+    }
+
+
+    private String searchMap (Map<String, Object> operand, String key) {
+
+        String type = (String) operand.get("@type");
+        Map<String, Object> child;
+        if (type.equals("koral:token") && operand.containsKey("wrap")) {
+            return searchMap((Map<String, Object>) operand.get("wrap"), key);
+        }
+        else if (type.equals("koral:span")) {
+            // EM: legacy, should be deprecated later
+            if (operand.containsKey(key)) {
+                return (String) operand.get(key);
+            }
+            else if (operand.containsKey("wrap")) {
+                return searchMap((Map<String, Object>) operand.get("wrap"),
+                        key);
+            }
+        }
+        else if (type.equals("koral:term")) {
+            if (operand.containsKey(key)) {
+                return (String) operand.get(key);
+            }
+        }
+        else {
+            addError(StatusCodes.MALFORMED_QUERY,
+                    "Cannot determine the " + key + ".");
+        }
+
+        return null;
+    }
+
+
+    private void inheritFoundryAndLayer (String edgeValue,
+            Map<String, Object> operand1, Map<String, Object> operand2) {
+
+        Map<String, Object> attribute = KoralObjectGenerator.makeTerm();
+        attribute.put("key", edgeValue);
+        attribute.put("match", KoralMatchOperator.EQUALS.toString());
+        operand1.put("attr", attribute);
+
+        if (operand1.containsKey("layer")) {
+            attribute.put("layer", operand1.get("layer"));
+            if (operand1.containsKey("foundry")) {
+                attribute.put("foundry", operand1.get("foundry"));
+            }
+        }
+        else if (operand2.containsKey("layer")) {
+            attribute.put("layer", operand2.get("layer"));
+            if (operand2.containsKey("foundry")) {
+                attribute.put("foundry", operand2.get("foundry"));
+            }
+        }
+        else if (operand1.containsKey("foundry")) {
+            attribute.put("foundry", operand1.get("foundry"));
+        }
+        else if (operand2.containsKey("foundry")) {
+            attribute.put("foundry", operand2.get("foundry"));
+        }
+    }
+
+
     /**
      * Parses a unary_linguistic_operator node. Possible operators
      * are:
@@ -849,39 +962,18 @@
             //            relation = KoralObjectGenerator.makeRelation();
             relation = new HashMap<String, Object>();
             relation.put("groupType", "hierarchy");
-            //            ParseTree qName = getFirstChildWithCat(operatorNode, "qName");
+            // Ignored
+            // ParseTree edgeType = getFirstChildWithCat(operatorNode, "edgeType");
             ParseTree edgeSpecNode = getFirstChildWithCat(operatorNode,
                     "edgeSpec");
             ParseTree star = getFirstChildWithCat(operatorNode, "*");
             ParseTree rangeSpec = getFirstChildWithCat(operatorNode,
                     "rangeSpec");
 
-            //            term.put("layer", "c");
-            //            if (qName != null)
             //                term = parseQNameNode(qName);
             if (edgeSpecNode != null) {
-                Map<String, Object> term = KoralObjectGenerator.makeTerm();
                 Map<String, Object> edgeSpec = parseEdgeSpec(edgeSpecNode);
-                String edgeSpecType = (String) edgeSpec.get("@type");
-                if (edgeSpecType.equals("koral:termGroup")) {
-                    ((ArrayList<Object>) edgeSpec.get("operands")).add(term);
-                    //                    term = edgeSpec;
-                }
-                //                else {
-                //                    term = KoralObjectGenerator.makeTermGroup(KoralTermGroupRelation.AND);
-                //                    ArrayList<Object> termGroupOperands = (ArrayList<Object>) term
-                //                            .get("operands");
-                //                    termGroupOperands.add(edgeSpec);
-                //                    Map<String, Object> constTerm = KoralObjectGenerator
-                //                            .makeTerm();
-                //                    constTerm.put("layer", "c");
-                //                    termGroupOperands.add(constTerm);
-                //                }
-                term = edgeSpec;
-                Map<String, Object> relType = KoralObjectGenerator
-                        .makeRelation();
-                relType.put("wrap", term);
-                relation.put("relType", relType);
+                relation.put("edgeValue", edgeSpec.get("value"));
             }
             if (star != null)
                 relation.put("boundary",
@@ -1019,18 +1111,23 @@
     @SuppressWarnings("unchecked")
     private Map<String, Object> parseEdgeSpec (ParseTree edgeSpec) {
         List<ParseTree> annos = getChildrenWithCat(edgeSpec, "edgeAnno");
-        if (annos.size() == 1)
-            return parseEdgeAnno(annos.get(0));
-        else {
-            Map<String, Object> termGroup = KoralObjectGenerator
-                    .makeTermGroup(KoralTermGroupRelation.AND);
-            ArrayList<Object> operands = (ArrayList<Object>) termGroup
-                    .get("operands");
-            for (ParseTree anno : annos) {
-                operands.add(parseEdgeAnno(anno));
-            }
-            return termGroup;
+        if (annos.size() != 1) {
+            addWarning(StatusCodes.MALFORMED_QUERY,
+                    "Multiple annotations are not allowed. "
+                            + "Processed only the first annotation.");
         }
+        return parseEdgeAnno(annos.get(0));
+
+        //        else {
+        //            Map<String, Object> termGroup = KoralObjectGenerator
+        //                    .makeTermGroup(KoralTermGroupRelation.AND);
+        //            ArrayList<Object> operands = (ArrayList<Object>) termGroup
+        //                    .get("operands");
+        //            for (ParseTree anno : annos) {
+        //                operands.add(parseEdgeAnno(anno));
+        //            }
+        //            return termGroup;
+        //        }
     }
 
 
@@ -1173,13 +1270,23 @@
     }
 
 
-    private void putAllButGroupType (Map<String, Object> container,
-            Map<String, Object> input) {
-        for (String key : input.keySet()) {
-            if (!key.equals("groupType")) {
-                container.put(key, input.get(key));
-            }
+    private void putAllBut (Map<String, Object> container,
+            Map<String, Object> input, String ... keys) {
+
+        Set<String> names = input.keySet();
+        for (String k : keys) {
+            names.remove(k);
         }
+
+        for (String n : names) {
+            container.put(n, input.get(n));
+        }
+
+        //        for (String key : input.keySet()) {
+        //            if (!key.equals("groupType")) {
+        //                container.put(key, input.get(key));
+        //            }
+        //        }
     }
 
 
diff --git a/src/test/java/de/ids_mannheim/korap/query/test/annis/DominanceTests.java b/src/test/java/de/ids_mannheim/korap/query/test/annis/DominanceTests.java
index 5a85703..66cbf84 100644
--- a/src/test/java/de/ids_mannheim/korap/query/test/annis/DominanceTests.java
+++ b/src/test/java/de/ids_mannheim/korap/query/test/annis/DominanceTests.java
@@ -39,6 +39,37 @@
 

 

     @Test

+    public void testDefaultTypedDominance ()

+            throws JsonProcessingException, IOException {

+        query = "node & node & #1 >edgeType #2";

+        qs.setQuery(query, "annis");

+        res = mapper.readTree(qs.toJSON());

+

+        assertEquals("koral:group", res.at("/query/@type").asText());

+        assertEquals("operation:hierarchy",

+                res.at("/query/operation").asText());

+        assertEquals("koral:span", res.at("/query/operands/0/@type").asText());

+        assertEquals("koral:span", res.at("/query/operands/1/@type").asText());

+    }

+

+

+    @Test

+    public void testTypedDominance ()

+            throws JsonProcessingException, IOException {

+        query = "node & node & #1 >secedge #2";

+        qs.setQuery(query, "annis");

+        res = mapper.readTree(qs.toJSON());

+

+        assertEquals("koral:group", res.at("/query/@type").asText());

+        assertEquals("operation:hierarchy",

+                res.at("/query/operation").asText());

+        assertEquals("koral:span", res.at("/query/operands/0/@type").asText());

+        assertTrue(res.at("/query/operands/0/attr").isMissingNode());

+        assertEquals("koral:span", res.at("/query/operands/1/@type").asText());

+    }

+

+

+    @Test

     public void testDominanceWithAnnotationOnFirstOperand ()

             throws JsonProcessingException, IOException {

         query = "cnx/c=\"np\" > node";

@@ -92,16 +123,20 @@
 

 

     @Test

-    public void testDominanceWithAbritraryReferences ()

+    public void testDominanceWithDifferentLayer ()

             throws JsonProcessingException, IOException {

-        query = "node & node & #2 > #1";

+        query = "cat=\"NP\" & pos=\"ADJ\" & #1 > #2";

         qs.setQuery(query, "annis");

         res = mapper.readTree(qs.toJSON());

         assertEquals("koral:group", res.at("/query/@type").asText());

         assertEquals("operation:hierarchy",

                 res.at("/query/operation").asText());

         assertEquals("koral:span", res.at("/query/operands/0/@type").asText());

-        assertEquals("koral:span", res.at("/query/operands/1/@type").asText());

+        assertEquals("NP", res.at("/query/operands/0/key").asText());

+        assertEquals("c", res.at("/query/operands/0/layer").asText());

+        assertEquals("koral:token", res.at("/query/operands/1/@type").asText());

+        assertEquals("ADJ", res.at("/query/operands/1/wrap/key").asText());

+        assertEquals("p", res.at("/query/operands/1/wrap/layer").asText());

     }

 

 

@@ -162,6 +197,65 @@
         res = mapper.readTree(qs.toJSON());

         assertEquals(0, res.at("/query/boundary/min").asInt());

         assertTrue(res.at("/query/boundary/max").isMissingNode());

+        

+        // same layers

+        query = "cat=\"NP\" & cnx/c=\"PP\" & #1 >2,4 #2";

+        qs.setQuery(query, "annis");

+        res = mapper.readTree(qs.toJSON());

+        

+        assertEquals("c", res.at("/query/operands/0/layer").asText());

+        assertEquals("c", res.at("/query/operands/1/layer").asText());

+        assertEquals(2, res.at("/query/boundary/min").asInt());

+        assertEquals(4, res.at("/query/boundary/max").asInt());

+        assertTrue(res.at("/errors").isMissingNode());

+    }

+

+

+    @Test

+    public void testIndirectDominanceWithDifferentLayers ()

+            throws JsonProcessingException, IOException {

+        query = "cat=\"NP\" & pos=\"ADJ\" & #1 >2,4 #2";

+        qs.setQuery(query, "annis");

+        res = mapper.readTree(qs.toJSON());

+

+        assertEquals(305, res.at("/errors/0/0").asInt());

+        assertEquals(

+                "Indirect dominance between operands of different layers is not possible.",

+                res.at("/errors/0/1").asText());

+

+        assertEquals("koral:group", res.at("/query/@type").asText());

+        assertEquals("operation:hierarchy",

+                res.at("/query/operation").asText());

+        assertEquals("koral:span", res.at("/query/operands/0/@type").asText());

+        assertEquals("NP", res.at("/query/operands/0/key").asText());

+        assertEquals("c", res.at("/query/operands/0/layer").asText());

+        assertEquals("koral:token", res.at("/query/operands/1/@type").asText());

+        assertEquals("ADJ", res.at("/query/operands/1/wrap/key").asText());

+        assertEquals("p", res.at("/query/operands/1/wrap/layer").asText());

+    }

+

+    @Test

+    public void testIndirectDominanceWithFoundries ()

+            throws JsonProcessingException, IOException {

+        

+        query = "opennlp/c=\"NP\" & cnx/c=\"PP\" & #1 >2,4 #2";

+        qs.setQuery(query, "annis");

+        res = mapper.readTree(qs.toJSON());

+        

+        assertEquals(305, res.at("/errors/0/0").asInt());

+        assertEquals(

+                "Indirect dominance between operands of different foundries is not possible.",

+                res.at("/errors/0/1").asText());

+

+        assertEquals("koral:group", res.at("/query/@type").asText());

+        assertEquals("operation:hierarchy",

+                res.at("/query/operation").asText());

+        assertEquals("koral:span", res.at("/query/operands/0/@type").asText());

+        assertEquals("NP", res.at("/query/operands/0/key").asText());

+        assertEquals("c", res.at("/query/operands/0/layer").asText());

+        assertEquals("koral:span", res.at("/query/operands/1/@type").asText());

+        assertEquals("PP", res.at("/query/operands/1/key").asText());

+        assertEquals("c", res.at("/query/operands/1/layer").asText());

     }

 

 

@@ -172,67 +266,81 @@
         //coordinates the func=SB term and requires a "c"-layer term (consituency relation/dominance)

         qs.setQuery(query, "annis");

         res = mapper.readTree(qs.toJSON());

-        //        System.out.println(res.asText());

         assertEquals("operation:hierarchy",

                 res.at("/query/operation").asText());

-        assertEquals("koral:relation", res.at("/query/relType/@type").asText());

+        assertEquals("koral:span", res.at("/query/operands/0/@type").asText());

         assertEquals("koral:term",

-                res.at("/query/relType/wrap/@type").asText());

-        assertEquals("func", res.at("/query/relType/wrap/key").asText());

-        assertEquals("SBJ", res.at("/query/relType/wrap/value").asText());

+                res.at("/query/operands/0/attr/@type").asText());

+        assertEquals("match:eq",

+                res.at("/query/operands/0/attr/match").asText());

+        assertEquals("SBJ", res.at("/query/operands/0/attr/key").asText());

+        assertEquals("koral:token", res.at("/query/operands/1/@type").asText());

+        assertEquals("koral:term",

+                res.at("/query/operands/1/wrap/@type").asText());

+        assertEquals("Mann", res.at("/query/operands/1/wrap/key").asText());

+        assertEquals("match:eq",

+                res.at("/query/operands/1/wrap/match").asText());

     }

 

 

     @Test

-    public void testDominanceWithLayerAndLabel ()

+    public void testDominanceWithLayerInLabel ()

             throws JsonProcessingException, IOException {

-        query = "\"Mann\" & node & #2 >[c:func=\"SBJ\"] #1";

+        query = "\"Mann\" & node & " + "#2 >[c:func=\"SBJ\"] #1";

         qs.setQuery(query, "annis");

         res = mapper.readTree(qs.toJSON());

         assertEquals("operation:hierarchy",

                 res.at("/query/operation").asText());

-        assertEquals("koral:relation", res.at("/query/relType/@type").asText());

+        assertEquals("koral:span", res.at("/query/operands/0/@type").asText());

         assertEquals("koral:term",

-                res.at("/query/relType/wrap/@type").asText());

-        assertEquals("c", res.at("/query/relType/wrap/layer").asText());

-        assertEquals("func", res.at("/query/relType/wrap/key").asText());

-        assertEquals("SBJ", res.at("/query/relType/wrap/value").asText());

+                res.at("/query/operands/0/attr/@type").asText());

+        assertEquals("match:eq",

+                res.at("/query/operands/0/attr/match").asText());

+        assertEquals("SBJ", res.at("/query/operands/0/attr/key").asText());

+        assertTrue("SBJ",

+                res.at("/query/operands/0/attr/layer").isMissingNode());

+        assertTrue("SBJ",

+                res.at("/query/operands/0/attr/value").isMissingNode());

     }

 

 

     @Test

+    public void testDominanceWithTypeAndLabel ()

+            throws JsonProcessingException, IOException {

+        query = "node & node & #2 >rst[rst:name=\"evidence\"] #1";

+        //coordinates the func=SB term and requires a "c"-layer term (consituency relation/dominance)

+        qs.setQuery(query, "annis");

+        res = mapper.readTree(qs.toJSON());

+        assertEquals("operation:hierarchy",

+                res.at("/query/operation").asText());

+        assertEquals("koral:span", res.at("/query/operands/0/@type").asText());

+        assertEquals("koral:term",

+                res.at("/query/operands/0/attr/@type").asText());

+        assertEquals("match:eq",

+                res.at("/query/operands/0/attr/match").asText());

+        assertEquals("evidence", res.at("/query/operands/0/attr/key").asText());

+        assertEquals("koral:span", res.at("/query/operands/1/@type").asText());

+    }

+

+

+

+    @Test

     public void testDominanceWithMultipleLabels ()

             throws JsonProcessingException, IOException {

-        query = "corenlp/c=\"VP\" & corenlp/c=\"NP\" & #1 >[corenlp/c:func=\"PP\" corenlp/c:func=\"PN\"] #2";

+        query = "corenlp/c=\"VP\" & corenlp/c=\"NP\" & "

+                + "#1 >[corenlp/c:func=\"PP\" corenlp/c:func=\"PN\"] #2";

         qs.setQuery(query, "annis");

         res = mapper.readTree(qs.toJSON());

-        System.out.println(res.asText());

-        assertEquals("operation:hierarchy",

-                res.at("/query/operation").asText());

-        assertEquals("koral:relation", res.at("/query/relType/@type").asText());

-        assertEquals("koral:termGroup",

-                res.at("/query/relType/wrap/@type").asText());

-        assertEquals("relation:and",

-                res.at("/query/relType/wrap/relation").asText());

-        assertEquals("corenlp", res.at("/query/relType/wrap/operands/0/foundry").asText());

-        assertEquals("c", res.at("/query/relType/wrap/operands/0/layer").asText());

-        assertEquals("func", res.at("/query/relType/wrap/operands/0/key").asText());

-        assertEquals("PP", res.at("/query/relType/wrap/operands/0/value").asText());

-        

-        assertEquals("corenlp", res.at("/query/relType/wrap/operands/1/foundry").asText());

-        assertEquals("c", res.at("/query/relType/wrap/operands/1/layer").asText());

-        assertEquals("func", res.at("/query/relType/wrap/operands/1/key").asText());

-        assertEquals("PN", res.at("/query/relType/wrap/operands/1/value").asText());

+        assertEquals(302, res.at("/errors/0/0").asInt());

     }

 

 

     @Test

     public void testMultipleDominance ()

             throws JsonProcessingException, IOException {

-        query = "cat=\"CP\" & cat=\"VP\" & cat=\"NP\" & #1 > #2 > #3";

+        query = "cat=\"CP\" & cat=\"VP\" & cat=\"NP\" & #1 > #2 & #2 > #3";

         qs.setQuery(query, "annis");

         res = mapper.readTree(qs.toJSON());

-        //        System.out.println(res.asText());

         assertEquals("koral:group", res.at("/query/@type").asText());

         assertEquals("operation:hierarchy",

                 res.at("/query/operation").asText());

@@ -269,10 +377,10 @@
     @Test

     public void testMultipleDominance2 ()

             throws JsonProcessingException, IOException {

-        query = "cat=\"CP\" & cat=\"VP\" & cat=\"NP\" & cat=\"DP\" & #1 > #2 > #3 > #4";

+        query = "cat=\"CP\" & cat=\"VP\" & cat=\"NP\" & cat=\"DP\""

+                + " & #1 > #2 > #3 > #4";

         qs.setQuery(query, "annis");

         res = mapper.readTree(qs.toJSON());

-        System.out.println(res.asText());

 

         assertEquals("koral:group", res.at("/query/@type").asText());

         assertEquals("operation:hierarchy",