/**
* Copyright (c) 2015 committers of YAKINDU and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* Contributors:
* committers of YAKINDU - initial API and implementation
*
*/
package org.yakindu.sct.model.sexec.transformation.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.yakindu.sct.model.sexec.transformation.test.SCTTestUtil.TYPE_INTEGER;
import static org.yakindu.sct.model.sgraph.test.util.SGraphTestFactory._createEntry;
import static org.yakindu.sct.model.sgraph.test.util.SGraphTestFactory._createRegion;
import static org.yakindu.sct.model.sgraph.test.util.SGraphTestFactory._createState;
import static org.yakindu.sct.model.sgraph.test.util.SGraphTestFactory._createStatechart;
import static org.yakindu.sct.model.sgraph.test.util.SGraphTestFactory._createTransition;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createAlwaysEventSpec;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createEntryAction;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createEventDefinition;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createExitAction;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createInterfaceScope;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createLocalReaction;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createReactionTrigger;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createRegularEventSpec;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createTimeEventSpec;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createTimeTriggeredReaction;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createValue;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createVariableAssignment;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory._createVariableDefinition;
import static org.yakindu.sct.model.stext.test.util.StextTestFactory.createGuardExpression;
import org.junit.Test;
import org.yakindu.base.base.NamedElement;
import org.yakindu.base.expressions.expressions.AssignmentExpression;
import org.yakindu.base.expressions.expressions.AssignmentOperator;
import org.yakindu.base.expressions.expressions.BoolLiteral;
import org.yakindu.base.expressions.expressions.ElementReferenceExpression;
import org.yakindu.base.expressions.expressions.Expression;
import org.yakindu.base.expressions.expressions.IntLiteral;
import org.yakindu.base.expressions.expressions.Literal;
import org.yakindu.base.expressions.expressions.LogicalAndExpression;
import org.yakindu.base.expressions.expressions.LogicalOrExpression;
import org.yakindu.base.expressions.expressions.MultiplicativeOperator;
import org.yakindu.base.expressions.expressions.NumericalMultiplyDivideExpression;
import org.yakindu.base.expressions.expressions.ParenthesizedExpression;
import org.yakindu.base.expressions.expressions.PrimitiveValueExpression;
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.ScheduleTimeEvent;
import org.yakindu.sct.model.sexec.Sequence;
import org.yakindu.sct.model.sexec.TimeEvent;
import org.yakindu.sct.model.sexec.UnscheduleTimeEvent;
import org.yakindu.sct.model.sgraph.Entry;
import org.yakindu.sct.model.sgraph.EntryKind;
import org.yakindu.sct.model.sgraph.Region;
import org.yakindu.sct.model.sgraph.SGraphFactory;
import org.yakindu.sct.model.sgraph.Scope;
import org.yakindu.sct.model.sgraph.State;
import org.yakindu.sct.model.sgraph.Statechart;
import org.yakindu.sct.model.sgraph.Transition;
import org.yakindu.sct.model.stext.stext.EventDefinition;
import org.yakindu.sct.model.stext.stext.LocalReaction;
import org.yakindu.sct.model.stext.stext.ReactionEffect;
import org.yakindu.sct.model.stext.stext.ReactionTrigger;
import org.yakindu.sct.model.stext.stext.StextFactory;
import org.yakindu.sct.model.stext.stext.TimeEventType;
import org.yakindu.sct.model.stext.stext.TimeUnit;
import org.yakindu.sct.model.stext.stext.VariableDefinition;
public class ModelSequencerStateReactionTest extends ModelSequencerTest {
/**
* Single trigger events of a Reaction Trigger will be converted into a
* single condition that consists of a ElementReferenceExpression to the
* corresponding event definition.
*/
@Test
public void testSingleRegularEventTriggerCondition() {
EventDefinition e1 = _createEventDefinition("e1", null);
ReactionTrigger tr1 = _createReactionTrigger(null);
_createRegularEventSpec(e1, tr1);
Expression s = behaviorMapping.buildCondition(tr1);
assertClass(ElementReferenceExpression.class, s);
}
/**
* Multiple trigger events of a ReactionTrigger will be converted to a
* condition that consists of a ElementReferenceExpressions connected by
* LogicalOrExpressions.
*
* e1, e1 -> e1 || e2
*
*/
@Test
public void testMultipleRegularEventTriggerCondition() {
EventDefinition e1 = _createEventDefinition("e1", null);
EventDefinition e2 = _createEventDefinition("e2", null);
ReactionTrigger tr1 = _createReactionTrigger(null);
_createRegularEventSpec(e1, tr1);
_createRegularEventSpec(e2, tr1);
Expression s = behaviorMapping.buildCondition(tr1);
assertTrue(s instanceof LogicalOrExpression);
assertClass(ElementReferenceExpression.class,
((LogicalOrExpression) s).getLeftOperand());
assertClass(ElementReferenceExpression.class,
((LogicalOrExpression) s).getRightOperand());
}
public static void assertBoolLiteral(boolean value, Literal lit) {
assertTrue("Literal is no BoolLiteral", lit instanceof BoolLiteral);
assertEquals(value, ((BoolLiteral) lit).isValue());
}
public static void assertIntLiteral(int value, Literal lit) {
assertTrue("Literal is no IntLiteral", lit instanceof IntLiteral);
assertEquals(value, ((IntLiteral) lit).getValue());
}
/**
* The 'always' trigger event will be converted to a simple 'true'
* condition.
*/
@Test
public void testAlwaysTriggerCondition() {
ReactionTrigger tr1 = _createReactionTrigger(null);
_createAlwaysEventSpec(tr1);
Expression s = behaviorMapping.buildCondition(tr1);
assertNotNull(s);
assertTrue(s instanceof PrimitiveValueExpression);
assertBoolLiteral(true, ((PrimitiveValueExpression) s).getValue());
}
@Test
public void testTransitionCheckSequenceWithoutGuard() {
EventDefinition e1 = _createEventDefinition("e1", null);
EventDefinition e2 = _createEventDefinition("e2", null);
ReactionTrigger tr1 = _createReactionTrigger(null);
_createRegularEventSpec(e1, tr1);
_createRegularEventSpec(e2, tr1);
Transition t = SGraphFactory.eINSTANCE.createTransition();
t.setTrigger(tr1);
Statechart sc = _createStatechart("test");
Region region = _createRegion("r1", sc);
t.setSource(_createState("A", region));
t.setTarget(_createState("B", region));
Reaction reaction = behaviorMapping.mapTransition(t);
assertTrue(reaction.getCheck().getCondition() instanceof LogicalOrExpression);
assertClass(ElementReferenceExpression.class,
((LogicalOrExpression) reaction.getCheck().getCondition())
.getLeftOperand());
assertClass(ElementReferenceExpression.class,
((LogicalOrExpression) reaction.getCheck().getCondition())
.getRightOperand());
assertEquals(
e1.getName(),
((NamedElement) ((ElementReferenceExpression) ((LogicalOrExpression) reaction
.getCheck().getCondition()).getLeftOperand())
.getReference()).getName());
assertEquals(
e2.getName(),
((NamedElement) ((ElementReferenceExpression) ((LogicalOrExpression) reaction
.getCheck().getCondition()).getRightOperand())
.getReference()).getName());
}
@Test
public void testTransitionCheckSequenceWithGuard() {
EventDefinition e1 = _createEventDefinition("e1", null);
EventDefinition e2 = _createEventDefinition("e2", null);
ReactionTrigger tr1 = _createReactionTrigger(null);
_createRegularEventSpec(e1, tr1);
_createRegularEventSpec(e2, tr1);
PrimitiveValueExpression exp = _createValue(false);
tr1.setGuard(createGuardExpression(exp));
Transition t = SGraphFactory.eINSTANCE.createTransition();
t.setTrigger(tr1);
Statechart sc = _createStatechart("test");
Region region = _createRegion("r1", sc);
t.setSource(_createState("A", region));
t.setTarget(_createState("B", region));
Reaction reaction = behaviorMapping.mapTransition(t);
// now check the expression structure ...
// the root is an and condition with the trigger check as the first
// (left) part and the guard as the right (second) part.
LogicalAndExpression and = (LogicalAndExpression) reaction.getCheck()
.getCondition();
ParenthesizedExpression parenthesis = (ParenthesizedExpression) and
.getLeftOperand();
LogicalOrExpression triggerCheck = (LogicalOrExpression) parenthesis
.getExpression();
PrimitiveValueExpression guardCheck = (PrimitiveValueExpression) ((ParenthesizedExpression) and
.getRightOperand()).getExpression();
assertClass(ElementReferenceExpression.class,
triggerCheck.getLeftOperand());
assertClass(ElementReferenceExpression.class,
triggerCheck.getRightOperand());
assertEquals(e1.getName(),
((NamedElement) ((ElementReferenceExpression) triggerCheck
.getLeftOperand()).getReference()).getName());
assertEquals(e2.getName(),
((NamedElement) ((ElementReferenceExpression) triggerCheck
.getRightOperand()).getReference()).getName());
assertBoolLiteral(false, guardCheck.getValue());
}
@Test
public void testTransitionCheckSequenceWithoutTrigger() {
ReactionTrigger tr1 = _createReactionTrigger(null);
PrimitiveValueExpression exp = _createValue(false);
tr1.setGuard(createGuardExpression(exp));
Transition t = SGraphFactory.eINSTANCE.createTransition();
t.setTrigger(tr1);
Statechart sc = _createStatechart("test");
Region region = _createRegion("r1", sc);
t.setSource(_createState("A", region));
t.setTarget(_createState("B", region));
Reaction reaction = behaviorMapping.mapTransition(t);
// now check the expression structure ...
// the root is an and condition with the trigger check as the first
// (left) part and the guard as the right (second) part.
PrimitiveValueExpression guard = (PrimitiveValueExpression) reaction
.getCheck().getCondition();
assertBoolLiteral(false, guard.getValue());
}
/**
* If a entry trigger is combined with a guard condition then the entry
* action is executed conditionally with this trigger.
*/
@Test
public void testEntryActionWithGuard() {
Statechart sc = _createStatechart("test");
Scope scope = _createInterfaceScope("interface", sc);
VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER,
scope);
Region r = _createRegion("main", sc);
Entry e = _createEntry(EntryKind.INITIAL, null, r);
State s1 = _createState("s1", r);
State s2 = _createState("s2", r);
_createTransition(e, s1);
_createTransition(s1, s2);
LocalReaction entryAction = _createEntryAction(s2);
_createVariableAssignment(v1, AssignmentOperator.ASSIGN,
_createValue(42), (ReactionEffect) entryAction.getEffect());
((ReactionTrigger) entryAction.getTrigger())
.setGuard(createGuardExpression(_createValue(true)));
ExecutionFlow flow = sequencer.transform(sc);
ExecutionState _s1 = flow.getStates().get(0);
ExecutionState _s2 = flow.getStates().get(1);
assertEquals(s1.getName(), _s1.getSimpleName());
assertEquals(s2.getName(), _s2.getSimpleName());
Sequence _entrySeq = (Sequence) _s2.getEntryAction();
assertClass(If.class, _entrySeq.getSteps().get(0));
assertClass(PrimitiveValueExpression.class, ((If) _entrySeq.getSteps()
.get(0)).getCheck().getCondition());
assertAssignment(
((Sequence) ((If) _entrySeq.getSteps().get(0)).getThenStep())
.getSteps().get(0), "v1", AssignmentOperator.ASSIGN,
"42");
}
/**
* If a entry trigger is combined with a guard condition then the entry
* action is executed conditionally with this trigger.
*/
@Test
public void testEntryActionWithoutGuard() {
Statechart sc = _createStatechart("test");
Scope scope = _createInterfaceScope("interface", sc);
VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER,
scope);
Region r = _createRegion("main", sc);
Entry e = _createEntry(EntryKind.INITIAL, null, r);
State s1 = _createState("s1", r);
State s2 = _createState("s2", r);
_createTransition(e, s1);
_createTransition(s1, s2);
LocalReaction entryAction = _createEntryAction(s2);
_createVariableAssignment(v1, AssignmentOperator.ASSIGN,
_createValue(42), (ReactionEffect) entryAction.getEffect());
// ((ReactionTrigger)entryAction.getTrigger()).setGuardExpression(_createValue(true));
ExecutionFlow flow = sequencer.transform(sc);
ExecutionState _s1 = flow.getStates().get(0);
ExecutionState _s2 = flow.getStates().get(1);
assertEquals(s1.getName(), _s1.getSimpleName());
assertEquals(s2.getName(), _s2.getSimpleName());
Sequence _entrySeq = (Sequence) _s2.getEntryAction();
assertClass(Sequence.class, _entrySeq.getSteps().get(0));
assertAssignment(((Sequence) _entrySeq.getSteps().get(0)).getSteps()
.get(0), "v1", AssignmentOperator.ASSIGN, "42");
}
/**
* If a entry trigger is combined with a guard condition then the entry
* action is executed conditionally with this trigger.
*/
@Test
public void testExitActionWithGuard() {
Statechart sc = _createStatechart("test");
Scope scope = _createInterfaceScope("interface", sc);
VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER,
scope);
Region r = _createRegion("main", sc);
Entry e = _createEntry(EntryKind.INITIAL, null, r);
State s1 = _createState("s1", r);
State s2 = _createState("s2", r);
_createTransition(e, s1);
_createTransition(s1, s2);
LocalReaction exitAction = _createExitAction(s2);
_createVariableAssignment(v1, AssignmentOperator.ASSIGN,
_createValue(42), (ReactionEffect) exitAction.getEffect());
((ReactionTrigger) exitAction.getTrigger())
.setGuard(createGuardExpression(_createValue(true)));
ExecutionFlow flow = sequencer.transform(sc);
ExecutionState _s1 = flow.getStates().get(0);
ExecutionState _s2 = flow.getStates().get(1);
assertEquals(s1.getName(), _s1.getSimpleName());
assertEquals(s2.getName(), _s2.getSimpleName());
Sequence _exitSeq = (Sequence) _s2.getExitAction();
assertClass(If.class, _exitSeq.getSteps().get(0));
assertClass(PrimitiveValueExpression.class, ((If) _exitSeq.getSteps()
.get(0)).getCheck().getCondition());
assertAssignment(
((Sequence) ((If) _exitSeq.getSteps().get(0)).getThenStep())
.getSteps().get(0), "v1", AssignmentOperator.ASSIGN,
"42");
}
/**
* If a entry trigger is combined with a guard condition then the entry
* action is executed conditionally with this trigger.
*/
@Test
public void testExitActionWithoutGuard() {
Statechart sc = _createStatechart("test");
Scope scope = _createInterfaceScope("interface", sc);
VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER,
scope);
Region r = _createRegion("main", sc);
Entry e = _createEntry(EntryKind.INITIAL, null, r);
State s1 = _createState("s1", r);
State s2 = _createState("s2", r);
_createTransition(e, s1);
_createTransition(s1, s2);
LocalReaction exitAction = _createExitAction(s2);
_createVariableAssignment(v1, AssignmentOperator.ASSIGN,
_createValue(42), (ReactionEffect) exitAction.getEffect());
// ((ReactionTrigger)entryAction.getTrigger()).setGuardExpression(_createValue(true));
ExecutionFlow flow = sequencer.transform(sc);
ExecutionState _s1 = flow.getStates().get(0);
ExecutionState _s2 = flow.getStates().get(1);
assertEquals(s1.getName(), _s1.getSimpleName());
assertEquals(s2.getName(), _s2.getSimpleName());
Sequence _exitSeq = (Sequence) _s2.getExitAction();
assertClass(Sequence.class, _exitSeq.getSteps().get(0));
assertAssignment(((Sequence) _exitSeq.getSteps().get(0)).getSteps()
.get(0), "v1", AssignmentOperator.ASSIGN, "42");
}
/**
* If a time trigger is defined for a transition then an event must be
* introduced into the execution flow.
*/
@SuppressWarnings("unused")
@Test
public void testSingleTransitionTimeTrigger() {
Statechart sc = _createStatechart("test");
Scope scope = _createInterfaceScope("interface", sc);
VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER,
scope);
Region r = _createRegion("main", sc);
State s = _createState("s", r);
Transition t = _createTransition(s, s);
ReactionTrigger tr1 = _createReactionTrigger(t);
_createTimeEventSpec(TimeEventType.AFTER, _createValue(1),
TimeUnit.SECOND, tr1);
AssignmentExpression assign = _createVariableAssignment(v1,
AssignmentOperator.ASSIGN, _createValue(42),
(ReactionEffect) t.getEffect());
ExecutionFlow flow = sequencer.transform(sc);
// assert definition of time event
Scope timerScope = flow.getScopes().get(1);
assertTrue(timerScope.getDeclarations().get(0) instanceof TimeEvent);
TimeEvent te = (TimeEvent) timerScope.getDeclarations().get(0);
// assert that the reaction check checks the time event
assertEquals(1, flow.getStates().size());
ExecutionState _s = flow.getStates().get(0);
assertEquals(s.getName(), _s.getSimpleName());
If _if = (If) SCTTestUtil.flattenSequenceStepsAsList(
flow.getStates().get(0).getReactSequence()).get(0);
ElementReferenceExpression _ere = (ElementReferenceExpression) _if
.getCheck().getCondition();
assertSame(te, _ere.getReference());
// assert the scheduling of the time event during state entry
assertNotNull(_s.getEntryAction());
Sequence entryAction = (Sequence) _s.getEntryAction();
ScheduleTimeEvent ste = (ScheduleTimeEvent) entryAction.getSteps().get(
0);
assertSame(te, ste.getTimeEvent());
NumericalMultiplyDivideExpression multiply = (NumericalMultiplyDivideExpression) ste
.getTimeValue();
assertIntLiteral(1,
((PrimitiveValueExpression) multiply.getLeftOperand())
.getValue());
assertIntLiteral(1000,
((PrimitiveValueExpression) multiply.getRightOperand())
.getValue());
assertEquals(MultiplicativeOperator.MUL, multiply.getOperator());
// assert the unscheduling of the time events during state exit
assertNotNull(_s.getExitAction());
Sequence exitAction = (Sequence) _s.getExitAction();
UnscheduleTimeEvent ute = (UnscheduleTimeEvent) exitAction.getSteps()
.get(0);
assertSame(te, ute.getTimeEvent());
}
/**
*
*/
@SuppressWarnings("unused")
@Test
public void testSingleLocalTimeTrigger() {
Statechart sc = _createStatechart("test");
Scope scope = _createInterfaceScope("interface", sc);
VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER,
scope);
Region r = _createRegion("main", sc);
State s = _createState("s", r);
LocalReaction timeTriggeredReaction = _createTimeTriggeredReaction(s,
TimeEventType.AFTER, _createValue(2), TimeUnit.MILLISECOND);
AssignmentExpression assign = _createVariableAssignment(v1,
AssignmentOperator.ASSIGN, _createValue(42),
(ReactionEffect) timeTriggeredReaction.getEffect());
ExecutionFlow flow = sequencer.transform(sc);
Scope timerScope = flow.getScopes().get(1);
assertTrue(timerScope.getDeclarations().get(0) instanceof TimeEvent);
TimeEvent te = (TimeEvent) timerScope.getDeclarations().get(0);
// assert that the reaction check checks the time event
ExecutionState _s = flow.getStates().get(0);
// assert the scheduling of the time event during state entry
assertNotNull(_s.getEntryAction());
Sequence entryAction = (Sequence) _s.getEntryAction();
ScheduleTimeEvent ste = (ScheduleTimeEvent) entryAction.getSteps().get(
0);
assertSame(te, ste.getTimeEvent());
PrimitiveValueExpression value = (PrimitiveValueExpression) ste
.getTimeValue();
assertIntLiteral(2, value.getValue());
assertNotNull(_s.getExitAction());
Sequence exitAction = (Sequence) _s.getExitAction();
UnscheduleTimeEvent ute = (UnscheduleTimeEvent) exitAction.getSteps()
.get(0);
assertSame(te, ute.getTimeEvent());
}
/**
* Local reactions must be created for behavior with 'always' trigger
*/
@SuppressWarnings("unused")
@Test
public void testAlwaysLocalReaction() {
Statechart sc = _createStatechart("test");
Scope scope = _createInterfaceScope("interface", sc);
VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER,
scope);
Region r = _createRegion("main", sc);
State s = _createState("s", r);
LocalReaction timeTriggeredReaction = _createLocalReaction(s,
StextFactory.eINSTANCE.createAlwaysEvent());
AssignmentExpression assign = _createVariableAssignment(v1,
AssignmentOperator.ASSIGN, _createValue(42),
(ReactionEffect) timeTriggeredReaction.getEffect());
ExecutionFlow flow = sequencer.transform(sc);
ExecutionState _s = flow.getStates().get(0);
// assert that a local reaction is created
Reaction reaction = _s.getReactions().get(0);
PrimitiveValueExpression pve = (PrimitiveValueExpression) reaction
.getCheck().getCondition();
assertBoolLiteral(true, pve.getValue());
}
}