Browse Source

Local reactions and tests for statechart (YAKHMI-110)

benjamin.schwertfeger@gmail.com 13 years ago
parent
commit
b5a70fce91

+ 1 - 1
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/transformation/ModelSequencer.xtend

@@ -138,9 +138,9 @@ class ModelSequencer {
 		sc.mapChoiceTransitions(ef)
 		
 		sc.defineEntryReactions(ef)
-		ef.defineStatechartReaction(sc)
 		ef.defineRegularStateReactions(sc)
 		ef.definePseudoStateReactions(sc)
+		ef.defineStatechartReaction(sc)
 		
 		// retarget declaration refs
 		ef.retargetDeclRefs

+ 19 - 6
plugins/org.yakindu.sct.model.sexec/src/org/yakindu/sct/model/sexec/transformation/ReactionBuilder.xtend

@@ -19,6 +19,7 @@ import org.yakindu.sct.model.sexec.ExecutionNode
 import org.yakindu.sct.model.sexec.Step
 import org.yakindu.sct.model.sgraph.FinalState
 import org.eclipse.xtext.EcoreUtil2
+import com.google.common.collect.Iterables
 
 class ReactionBuilder {
 	@Inject extension SexecElementMapping mapping
@@ -28,9 +29,21 @@ class ReactionBuilder {
 	@Inject extension TraceExtensions trace
 	
 	def defineStatechartReaction(ExecutionFlow flow, Statechart sc) {
-		val reaction = flow.createReactionSequence(null)
+		val sequence = sexec.factory.createSequence
+		sequence.name = "react"
+		sequence.comment = 'The reactions of statechart '+sc.name
+		
+		val leafStates = sc.allRegularStates.filter(s|s.leaf)
+		val sSwitch = sexec.factory.createStateSwitch
+		sequence.steps += sSwitch
+		for (leaf : leafStates.map(s|s.create)) {
+			val sCase = sexec.factory.createStateCase
+			sCase.state = leaf
+			sCase.step = leaf.reactSequence.newCall
+			sSwitch.cases += sCase
+		}
 		
-		flow.reactSequence = reaction
+		flow.reactSequence = sequence
 		return flow
 	}
 
@@ -84,11 +97,11 @@ class ReactionBuilder {
 	def Sequence defineCycle(RegularState state) {
 	
 		val execState = state.create
-		val parents = state.parentStates		
-		execState.reactSequence = parents.fold(null, [r, s | {
-			s.create.createReactionSequence(r)
+		val parents = state.parentStates
+		val parentNodes = Iterables::concat(parents.map(p|p.create as ExecutionNode),newHashSet(EcoreUtil2::getRootContainer(execState) as ExecutionNode))
+		execState.reactSequence = parentNodes.fold(null, [r, s | {
+			s.createReactionSequence(r)
 		}])
-		execState.reactSequence = (EcoreUtil2::getRootContainer(execState) as ExecutionFlow).createReactionSequence(execState.reactSequence)
 		
 		execState.reactSequence.name = 'react'
 		execState.reactSequence.comment = 'The reactions of state ' + state.name + '.'

+ 1 - 1
plugins/org.yakindu.sct.model.sexec/xtend-gen/org/yakindu/sct/model/sexec/transformation/ModelSequencer.java

@@ -106,9 +106,9 @@ public class ModelSequencer {
       this.behaviorMapping.mapLocalReactions(sc, ef);
       this.behaviorMapping.mapChoiceTransitions(sc, ef);
       this.reactBuilder.defineEntryReactions(sc, ef);
-      this.reactBuilder.defineStatechartReaction(ef, sc);
       this.reactBuilder.defineRegularStateReactions(ef, sc);
       this.reactBuilder.definePseudoStateReactions(ef, sc);
+      this.reactBuilder.defineStatechartReaction(ef, sc);
       this.retargetDeclRefs(ef);
       return ef;
     }

+ 66 - 16
plugins/org.yakindu.sct.model.sexec/xtend-gen/org/yakindu/sct/model/sexec/transformation/ReactionBuilder.java

@@ -1,12 +1,15 @@
 package org.yakindu.sct.model.sexec.transformation;
 
+import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
+import java.util.HashSet;
 import java.util.List;
 import org.eclipse.emf.common.util.EList;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.util.EcoreUtil;
 import org.eclipse.xtext.xbase.lib.BooleanExtensions;
 import org.eclipse.xtext.xbase.lib.CollectionExtensions;
+import org.eclipse.xtext.xbase.lib.CollectionLiterals;
 import org.eclipse.xtext.xbase.lib.Functions.Function1;
 import org.eclipse.xtext.xbase.lib.Functions.Function2;
 import org.eclipse.xtext.xbase.lib.IntegerExtensions;
@@ -29,6 +32,8 @@ import org.yakindu.sct.model.sexec.Reaction;
 import org.yakindu.sct.model.sexec.ReactionFired;
 import org.yakindu.sct.model.sexec.Sequence;
 import org.yakindu.sct.model.sexec.SexecFactory;
+import org.yakindu.sct.model.sexec.StateCase;
+import org.yakindu.sct.model.sexec.StateSwitch;
 import org.yakindu.sct.model.sexec.Step;
 import org.yakindu.sct.model.sexec.TraceNodeExecuted;
 import org.yakindu.sct.model.sexec.transformation.SexecElementMapping;
@@ -70,9 +75,48 @@ public class ReactionBuilder {
   
   public ExecutionFlow defineStatechartReaction(final ExecutionFlow flow, final Statechart sc) {
     {
-      Sequence _createReactionSequence = this.createReactionSequence(flow, null);
-      final Sequence reaction = _createReactionSequence;
-      flow.setReactSequence(reaction);
+      SexecFactory _factory = this.sexec.factory();
+      Sequence _createSequence = _factory.createSequence();
+      final Sequence sequence = _createSequence;
+      sequence.setName("react");
+      String _name = sc.getName();
+      String _operator_plus = StringExtensions.operator_plus("The reactions of statechart ", _name);
+      sequence.setComment(_operator_plus);
+      List<RegularState> _allRegularStates = this.sct.allRegularStates(sc);
+      final Function1<RegularState,Boolean> _function = new Function1<RegularState,Boolean>() {
+          public Boolean apply(final RegularState s) {
+            boolean _isLeaf = ReactionBuilder.this.sgraph.isLeaf(s);
+            return ((Boolean)_isLeaf);
+          }
+        };
+      Iterable<RegularState> _filter = IterableExtensions.<RegularState>filter(_allRegularStates, _function);
+      final Iterable<RegularState> leafStates = _filter;
+      SexecFactory _factory_1 = this.sexec.factory();
+      StateSwitch _createStateSwitch = _factory_1.createStateSwitch();
+      final StateSwitch sSwitch = _createStateSwitch;
+      EList<Step> _steps = sequence.getSteps();
+      CollectionExtensions.<Step>operator_add(_steps, sSwitch);
+      final Function1<RegularState,ExecutionState> _function_1 = new Function1<RegularState,ExecutionState>() {
+          public ExecutionState apply(final RegularState s_1) {
+            ExecutionState _create = ReactionBuilder.this.mapping.create(s_1);
+            return _create;
+          }
+        };
+      Iterable<ExecutionState> _map = IterableExtensions.<RegularState, ExecutionState>map(leafStates, _function_1);
+      for (final ExecutionState leaf : _map) {
+        {
+          SexecFactory _factory_2 = this.sexec.factory();
+          StateCase _createStateCase = _factory_2.createStateCase();
+          final StateCase sCase = _createStateCase;
+          sCase.setState(leaf);
+          Sequence _reactSequence = leaf.getReactSequence();
+          Call _newCall = this.mapping.newCall(_reactSequence);
+          sCase.setStep(_newCall);
+          EList<StateCase> _cases = sSwitch.getCases();
+          CollectionExtensions.<StateCase>operator_add(_cases, sCase);
+        }
+      }
+      flow.setReactSequence(sequence);
       return flow;
     }
   }
@@ -205,28 +249,34 @@ public class ReactionBuilder {
       final ExecutionState execState = _create;
       List<RegularState> _parentStates = this.sgraph.parentStates(state);
       final List<RegularState> parents = _parentStates;
-      final Function2<Sequence,RegularState,Sequence> _function = new Function2<Sequence,RegularState,Sequence>() {
-          public Sequence apply(final Sequence r , final RegularState s) {
-            ExecutionState _create_1 = ReactionBuilder.this.mapping.create(s);
-            Sequence _createReactionSequence = ReactionBuilder.this.createReactionSequence(_create_1, r);
+      final Function1<RegularState,ExecutionNode> _function = new Function1<RegularState,ExecutionNode>() {
+          public ExecutionNode apply(final RegularState p) {
+            ExecutionState _create_1 = ReactionBuilder.this.mapping.create(p);
+            return ((ExecutionNode) _create_1);
+          }
+        };
+      List<ExecutionNode> _map = ListExtensions.<RegularState, ExecutionNode>map(parents, _function);
+      EObject _rootContainer = EcoreUtil.getRootContainer(execState);
+      HashSet<ExecutionNode> _newHashSet = CollectionLiterals.<ExecutionNode>newHashSet(((ExecutionNode) _rootContainer));
+      Iterable<ExecutionNode> _concat = Iterables.<ExecutionNode>concat(_map, _newHashSet);
+      final Iterable<ExecutionNode> parentNodes = _concat;
+      final Function2<Sequence,ExecutionNode,Sequence> _function_1 = new Function2<Sequence,ExecutionNode,Sequence>() {
+          public Sequence apply(final Sequence r , final ExecutionNode s) {
+            Sequence _createReactionSequence = ReactionBuilder.this.createReactionSequence(s, r);
             return _createReactionSequence;
           }
         };
-      Sequence _fold = IterableExtensions.<RegularState, Sequence>fold(parents, null, _function);
+      Sequence _fold = IterableExtensions.<ExecutionNode, Sequence>fold(parentNodes, null, _function_1);
       execState.setReactSequence(_fold);
-      EObject _rootContainer = EcoreUtil.getRootContainer(execState);
       Sequence _reactSequence = execState.getReactSequence();
-      Sequence _createReactionSequence_1 = this.createReactionSequence(((ExecutionFlow) _rootContainer), _reactSequence);
-      execState.setReactSequence(_createReactionSequence_1);
+      _reactSequence.setName("react");
       Sequence _reactSequence_1 = execState.getReactSequence();
-      _reactSequence_1.setName("react");
-      Sequence _reactSequence_2 = execState.getReactSequence();
       String _name = state.getName();
       String _operator_plus = StringExtensions.operator_plus("The reactions of state ", _name);
       String _operator_plus_1 = StringExtensions.operator_plus(_operator_plus, ".");
-      _reactSequence_2.setComment(_operator_plus_1);
-      Sequence _reactSequence_3 = execState.getReactSequence();
-      return _reactSequence_3;
+      _reactSequence_1.setComment(_operator_plus_1);
+      Sequence _reactSequence_2 = execState.getReactSequence();
+      return _reactSequence_2;
     }
   }
   

+ 1 - 1
test-plugins/org.yakindu.sct.model.sexec.test/META-INF/MANIFEST.MF

@@ -6,7 +6,7 @@ Bundle-Version: 1.0.0.qualifier
 Bundle-Vendor: YAKINDU
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
 Require-Bundle: org.eclipse.core.runtime,
- org.junit4;bundle-version="4.8.1",
+ org.junit;bundle-version="4.8.1",
  org.apache.log4j;bundle-version="1.2.15",
  org.eclipse.xtend;bundle-version="1.1.0",
  org.eclipse.core.resources;bundle-version="3.7.100",

+ 9 - 2
test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/Assert.java

@@ -195,10 +195,17 @@ public class Assert {
 		return step.toString();
 	}
 
-	public static void assertClass(Class<?> clazz, Object actual) {
+	@SuppressWarnings("unchecked")
+	/**
+	 * Assertion, that the given Object is of type T. If it is, the casted object is returned.
+	 * @param clazz
+	 * @param actual
+	 * @return
+	 */
+	public static <T> T assertClass(Class<T> clazz, Object actual) {
 		assertTrue(clazz.getSimpleName() + " expected, but got "
 				+ actual.getClass().getSimpleName(), clazz.isInstance(actual));
-
+		return (T) actual;
 	}
 
 	public static void assertedOrder(Step step,

+ 122 - 0
test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/LocalReactionTest.java

@@ -0,0 +1,122 @@
+package org.yakindu.sct.model.sexec.transformation.test;
+
+import static org.junit.Assert.*;
+import static org.yakindu.sct.model.sexec.transformation.test.SCTTestUtil.*;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.yakindu.sct.model.sexec.CheckRef;
+import org.yakindu.sct.model.sexec.EnterState;
+import org.yakindu.sct.model.sexec.ExecutionFlow;
+import org.yakindu.sct.model.sexec.ExecutionState;
+import org.yakindu.sct.model.sexec.If;
+import org.yakindu.sct.model.sexec.Reaction;
+import org.yakindu.sct.model.sexec.Sequence;
+import org.yakindu.sct.model.sexec.StateCase;
+import org.yakindu.sct.model.sexec.StateSwitch;
+import org.yakindu.sct.model.sexec.Step;
+import org.yakindu.sct.model.sgraph.Region;
+import org.yakindu.sct.model.sgraph.State;
+import org.yakindu.sct.model.sgraph.Statechart;
+import org.yakindu.sct.model.stext.stext.AssignmentOperator;
+import org.yakindu.sct.model.stext.stext.InterfaceScope;
+import org.yakindu.sct.model.stext.stext.LocalReaction;
+import org.yakindu.sct.model.stext.stext.ReactionEffect;
+import org.yakindu.sct.model.stext.stext.VariableDefinition;
+
+public class LocalReactionTest extends ModelSequencerTest {
+
+	/**
+	 * The transition sequence must contain all exit actions for parent states
+	 * that will be left by a transition.
+	 */
+	@Test
+	public void testSCLocalReaction() {
+
+		Statechart sc = _createStatechart("sc");
+		{
+			LocalReaction lr0 = _createLocalReaction(sc,
+					_createAlwaysEventSpec(null));
+			VariableDefinition v = _createVariableDefinition("v", TYPE_INTEGER,
+					getOrCreateInternalScope(sc));
+			_createVariableAssignment(v, AssignmentOperator.ADD_ASSIGN,
+					_createValue(1), (ReactionEffect) lr0.getEffect());
+
+			Region r = _createRegion("r", sc);
+			{
+				State s1 = _createState("s1", r);
+				{
+					LocalReaction lr1 = _createLocalReaction(s1,
+							_createAlwaysEventSpec(null));
+					_createVariableAssignment(v, AssignmentOperator.ADD_ASSIGN,
+							_createValue(2), (ReactionEffect) lr1.getEffect());
+					_createEntryAssignment(v, s1, 1);
+
+					Region r_s1 = _createRegion("r", s1);
+					{
+						_createState("s3", r_s1);
+					}
+				}
+				State s2 = _createState("s2", r);
+				{
+					_createEntryAssignment(v, s2, 1);
+					Region r_s2 = _createRegion("r", s2);
+					{
+						_createState("s6", r_s2);
+					}
+				}
+			}
+		}
+
+		_createTransition(findState(sc, "s3"), findState(sc, "s6"));
+
+		ExecutionFlow flow = sequencer.transform(sc);
+
+		assertEquals(1, flow.getReactions().size());
+
+		ExecutionState _s1 = flow.getStates().get(0);
+		assertEquals("sc.r.s1", _s1.getName());
+		// assertEquals(1, _s1.getReactions().size());
+		ExecutionState _s3 = flow.getStates().get(1);
+		assertEquals("sc.r.s1.r.s3", _s3.getName());
+
+		ExecutionState _s2 = flow.getStates().get(2);
+		assertEquals("sc.r.s2", _s2.getName());
+		// assertEquals(1, _s2.getReactions().size());
+		ExecutionState _s6 = flow.getStates().get(3);
+		assertEquals("sc.r.s2.r.s6", _s6.getName());
+
+		Reaction _t = _s3.getReactions().get(0);
+		assertTrue(_t.isTransition());
+
+		// Check Stateswitch in flow
+		StateSwitch sSwitch = assertedSwitch(flow.getReactSequence().getSteps()
+				.get(0));
+		assertStateSwitch(sSwitch, _s3, _s6);
+		assertCall(assertedStateCase(sSwitch, _s3).getStep(),
+				_s3.getReactSequence());
+
+		// Check reactSequence of leaf state
+		Sequence _effect = (Sequence) _t.getEffect();
+
+		assertCall(_effect, 0, _s1.getExitSequence());
+		assertCall(_effect, 1, _s2.getEntryAction());
+		assertCall(_effect, 2, _s6.getEnterSequence());
+		assertEquals(3, _effect.getSteps().size());
+
+		List<Step> steps = flattenSequenceStepsAsList(_s3.getReactSequence());
+		If _if = assertClass(If.class, steps.get(0));
+		assertEquals(flow.getReactions().get(0).getCheck(),
+				assertClass(CheckRef.class, _if.getCheck()).getCheck());
+
+		_if = assertClass(If.class, steps.get(1));
+		assertEquals(_s1.getReactions().get(0).getCheck(),
+				assertClass(CheckRef.class, _if.getCheck()).getCheck());
+
+		_if = assertClass(If.class, steps.get(2));
+		assertNull(assertClass(CheckRef.class, _if.getCheck()).getCheck());
+		assertCall(_if.getThenStep(), _effect);
+	}
+
+}

+ 43 - 12
test-plugins/org.yakindu.sct.model.sexec.test/src/org/yakindu/sct/model/sexec/transformation/test/SCTTestUtil.java

@@ -15,6 +15,7 @@ import org.yakindu.sct.model.sgraph.Entry;
 import org.yakindu.sct.model.sgraph.EntryKind;
 import org.yakindu.sct.model.sgraph.FinalState;
 import org.yakindu.sct.model.sgraph.Reaction;
+import org.yakindu.sct.model.sgraph.ReactiveElement;
 import org.yakindu.sct.model.sgraph.Region;
 import org.yakindu.sct.model.sgraph.SGraphFactory;
 import org.yakindu.sct.model.sgraph.Scope;
@@ -41,6 +42,7 @@ import org.yakindu.sct.model.stext.stext.PrimitiveValueExpression;
 import org.yakindu.sct.model.stext.stext.ReactionEffect;
 import org.yakindu.sct.model.stext.stext.ReactionTrigger;
 import org.yakindu.sct.model.stext.stext.RegularEventSpec;
+import org.yakindu.sct.model.stext.stext.SimpleScope;
 import org.yakindu.sct.model.stext.stext.StextFactory;
 import org.yakindu.sct.model.stext.stext.TimeEventSpec;
 import org.yakindu.sct.model.stext.stext.TimeEventType;
@@ -270,6 +272,47 @@ public class SCTTestUtil {
 
 	public static LocalReaction _createLocalReaction(State parent,
 			EventSpec triggerEvent) {
+		LocalReaction reaction = _createLocalReaction(triggerEvent);
+
+		Scope scope = getOrCreateSimpleScope(parent);
+
+		scope.getDeclarations().add(reaction);
+
+		return reaction;
+	}
+
+	public static LocalReaction _createLocalReaction(Statechart parent,
+			EventSpec triggerEvent) {
+		LocalReaction reaction = _createLocalReaction(triggerEvent);
+
+		Scope scope = getOrCreateInternalScope(parent);
+
+		scope.getDeclarations().add(reaction);
+
+		return reaction;
+	}
+
+	public static SimpleScope getOrCreateSimpleScope(State state) {
+		for (Scope scope : state.getScopes()) {
+			if (scope instanceof SimpleScope) {
+				return (SimpleScope) scope;
+			}
+		}
+		SimpleScope scope = StextFactory.eINSTANCE.createSimpleScope();
+		state.getScopes().add(scope);
+		return scope;
+	}
+
+	public static InternalScope getOrCreateInternalScope(Statechart sc) {
+		for (Scope scope : sc.getScopes()) {
+			if (scope instanceof InternalScope) {
+				return (InternalScope) scope;
+			}
+		}
+		return _createInternalScope(sc);
+	}
+
+	public static LocalReaction _createLocalReaction(EventSpec triggerEvent) {
 		LocalReaction reaction = StextFactory.eINSTANCE.createLocalReaction();
 		ReactionTrigger trigger = StextFactory.eINSTANCE
 				.createReactionTrigger();
@@ -279,18 +322,6 @@ public class SCTTestUtil {
 			trigger.getTriggers().add(triggerEvent);
 		reaction.setTrigger(trigger);
 
-		Scope scope = null;
-		if (parent != null) {
-			if (parent.getScopes().size() > 0) {
-				scope = parent.getScopes().get(0);
-			} else {
-				scope = StextFactory.eINSTANCE.createSimpleScope();
-				parent.getScopes().add(scope);
-			}
-		}
-
-		scope.getDeclarations().add(reaction);
-
 		return reaction;
 	}