Merge pull request #112 from apache/bugfix/110-Usage-of-labels-within-macro-action-definition-is-broken

Issue #110: Usage of labels within macro action definition is broken
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/action/MacroAction.java b/ruta-core/src/main/java/org/apache/uima/ruta/action/MacroAction.java
index 28c654c..f3bb8f4 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/action/MacroAction.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/action/MacroAction.java
@@ -98,14 +98,6 @@
     }
   }
 
-  @Override
-  public void setLabel(String label) {
-    super.setLabel(label);
-    for (AbstractRutaAction action : actions) {
-      action.setLabel(label);
-    }
-  }
-
   public String getName() {
     return name;
   }
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaRule.java b/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaRule.java
index 7c6f653..105f419 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaRule.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaRule.java
@@ -21,10 +21,12 @@
 

 import java.util.ArrayList;

 import java.util.Collection;

+import java.util.HashSet;

 import java.util.LinkedHashMap;

 import java.util.List;

 import java.util.Map;

 import java.util.Map.Entry;

+import java.util.Set;

 

 import org.apache.commons.lang3.StringUtils;

 import org.apache.uima.cas.text.AnnotationFS;

@@ -33,6 +35,7 @@
 import org.apache.uima.ruta.RutaStatement;

 import org.apache.uima.ruta.RutaStream;

 import org.apache.uima.ruta.action.AbstractRutaAction;

+import org.apache.uima.ruta.action.MacroAction;

 import org.apache.uima.ruta.block.RutaBlock;

 import org.apache.uima.ruta.visitor.InferenceCrowd;

 

@@ -109,7 +112,7 @@
         ownLabels.add(ruleElement.getLabel());

       }

     }

-    fillLabelMapWithActions(ruleElement.getActions(), own);

+    fillLabelMapWithActions(ruleElement.getActions(), own, new HashSet<>());

     if (ruleElement instanceof ComposedRuleElement) {

       ComposedRuleElement cre = (ComposedRuleElement) ruleElement;

       List<RuleElement> ruleElements = cre.getRuleElements();

@@ -121,15 +124,26 @@
     fillLabelMapWithInlinedRules(ruleElement.getInlinedActionRuleBlocks());

   }

 

-  private void fillLabelMapWithActions(List<AbstractRutaAction> actions, boolean own) {

+  private void fillLabelMapWithActions(List<AbstractRutaAction> actions, boolean own,

+          Set<AbstractRutaAction> processedActions) {

     if (actions != null) {

       for (AbstractRutaAction action : actions) {

+        // TODO recursive declarations are not supported right now, but we should check it anyways

+        if (processedActions.contains(action)) {

+          continue;

+        }

+        processedActions.add(action);

+

         if (action != null && !StringUtils.isBlank(action.getLabel())) {

           labels.put(action.getLabel(), null);

           if (own) {

             ownLabels.add(action.getLabel());

           }

         }

+        if (action instanceof MacroAction) {

+          MacroAction macroAction = (MacroAction) action;

+          fillLabelMapWithActions(macroAction.getActions(), own, processedActions);

+        }

       }

     }

   }

diff --git a/ruta-core/src/test/java/org/apache/uima/ruta/action/MacroActionTest.java b/ruta-core/src/test/java/org/apache/uima/ruta/action/MacroActionTest.java
index 366899c..8641ad5 100644
--- a/ruta-core/src/test/java/org/apache/uima/ruta/action/MacroActionTest.java
+++ b/ruta-core/src/test/java/org/apache/uima/ruta/action/MacroActionTest.java
@@ -34,9 +34,12 @@
 import org.apache.uima.cas.Type;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.cas.text.AnnotationIndex;
+import org.apache.uima.fit.util.CasUtil;
 import org.apache.uima.ruta.engine.Ruta;
 import org.apache.uima.ruta.engine.RutaTestUtils;
 import org.apache.uima.ruta.engine.RutaTestUtils.TestFeature;
+import org.apache.uima.ruta.extensions.RutaParseRuntimeException;
+import org.assertj.core.api.Assertions;
 import org.junit.Ignore;
 import org.junit.Test;
 
@@ -89,7 +92,7 @@
   public void testLabel() throws Exception {
     String document = "Test";
     String script = "";
-    script += "ACTION doit() = MARK(T1);\n";
+    script += "ACTION doit() = t:MARK(T1);\n";
     script += "CW{-> t:doit()}-> {t{->T2};};\n";
 
     CAS cas = RutaTestUtils.getCAS(document);
@@ -100,6 +103,62 @@
   }
 
   @Test
+  public void testLabelCombination() throws Exception {
+    String document = "Father: DM2";
+    String script = "";
+    script += "ACTION link(ANNOTATION diag, ANNOTATION ref) = s:Subject,s.ref=ref,d.subject=s;\n";
+    script += "\"Father\"->T1;\n";
+    script += "\"DM2\"->Diagnosis;\n";
+    script += "t1:T1{-> link(d,t1)} COLON? d:Diagnosis;\n";
+
+    Map<String, String> typeMap = new TreeMap<String, String>();
+    String typeName1 = "Diagnosis";
+    typeMap.put(typeName1, CAS.TYPE_NAME_ANNOTATION);
+    String typeName2 = "Subject";
+    typeMap.put(typeName2, CAS.TYPE_NAME_ANNOTATION);
+
+    Map<String, List<TestFeature>> featureMap = new TreeMap<String, List<TestFeature>>();
+    List<TestFeature> list1 = new ArrayList<RutaTestUtils.TestFeature>();
+    List<TestFeature> list2 = new ArrayList<RutaTestUtils.TestFeature>();
+    featureMap.put(typeName1, list1);
+    featureMap.put(typeName2, list2);
+    String fn1 = "subject";
+    String fn2 = "ref";
+    list1.add(new TestFeature(fn1, "", typeName2));
+    list2.add(new TestFeature(fn2, "", CAS.TYPE_NAME_ANNOTATION));
+
+    CAS cas = RutaTestUtils.getCAS(document, typeMap, featureMap);
+    Ruta.apply(cas, script);
+
+    AnnotationFS actualDiagnosis = CasUtil.selectSingle(cas, CasUtil.getType(cas, typeName1));
+    AnnotationFS subjectValue = (AnnotationFS) actualDiagnosis
+            .getFeatureValue(actualDiagnosis.getType().getFeatureByBaseName(fn1));
+
+    Assertions.assertThat(actualDiagnosis).extracting(AnnotationFS::getCoveredText)
+            .isEqualTo("DM2");
+    Assertions.assertThat(subjectValue).extracting(AnnotationFS::getCoveredText)
+            .isEqualTo("Father");
+
+    AnnotationFS refValue = (AnnotationFS) subjectValue
+            .getFeatureValue(subjectValue.getType().getFeatureByBaseName(fn2));
+
+    Assertions.assertThat(refValue).extracting(AnnotationFS::getCoveredText).isEqualTo("Father");
+  }
+
+  @Test(expected = RutaParseRuntimeException.class)
+  public void testRecursiveDeclaration() throws Exception {
+    String document = "Test";
+    String script = "";
+    script += "ACTION action1() = action2();\n";
+    script += "ACTION action2() = action3();\n";
+    script += "ACTION action3() = action1();\n";
+    script += "CW{-> action1()};\n";
+
+    CAS cas = RutaTestUtils.getCAS(document);
+    Ruta.apply(cas, script);
+  }
+
+  @Test
   @Ignore
   public void testShareSameNameArgumentAndLabel() throws Exception {
     String document = "Day 5";