/** * Retrieves the target from an entry. TODO: validation of preconditions for entry targets e.g * every region needs an entry with appropriate target */ public State target(final Entry entry) { State _xifexpression = null; EList<Transition> _outgoingTransitions = entry == null ? (EList<Transition>) null : entry.getOutgoingTransitions(); boolean _notEquals = (!Objects.equal(_outgoingTransitions, null)); if (_notEquals) { State _xifexpression_1 = null; EList<Transition> _outgoingTransitions_1 = entry.getOutgoingTransitions(); int _size = _outgoingTransitions_1.size(); boolean _greaterThan = (_size > 0); if (_greaterThan) { State _xblockexpression = null; { EList<Transition> _outgoingTransitions_2 = entry.getOutgoingTransitions(); Transition _get = _outgoingTransitions_2.get(0); final Vertex target = _get.getTarget(); State _xifexpression_2 = null; if ((target instanceof State)) { _xifexpression_2 = ((State) target); } _xblockexpression = (_xifexpression_2); } _xifexpression_1 = _xblockexpression; } _xifexpression = _xifexpression_1; } return _xifexpression; }
protected void createEntryPoint(Edge edge, Diagram subdiagram) { Transition transition = (Transition) edge.getElement(); Region entryPointContainer = getEntryPointContainer(transition); Entry entryPoint = createSemanticEntryPoint(transition); // re-wire old transition to targeting the selected state transition.setTarget((State) subdiagram.getElement()); View oldTarget = edge.getTarget(); edge.setTarget(getContextObject()); // create node for entry point View entryPointContainerView = helper.getViewForSemanticElement(entryPointContainer, subdiagram); View entryPointRegionCompartment = ViewUtil.getChildBySemanticHint(entryPointContainerView, SemanticHints.REGION_COMPARTMENT); Node entryNode = ViewService.createNode( entryPointRegionCompartment, entryPoint, SemanticHints.ENTRY, preferencesHint); ViewService.createEdge( entryNode, oldTarget, entryPoint.getOutgoingTransitions().get(0), SemanticHints.TRANSITION, preferencesHint); addEntryPointSpec(transition, entryPoint); }
@Check(CheckType.FAST) public void disallowTrigger(Entry entry) { for (Transition transition : entry.getOutgoingTransitions()) { if (transition.getTrigger() != null) { error(ISSUE_ENTRY_WITH_TRIGGER, entry, null, -1); } } }
@Check(CheckType.FAST) public void checkExitPointSpecWithTrigger(Transition t) { if (!STextValidationModelUtils.getExitPointSpecs(t.getProperties()).isEmpty() && t.getTrigger() != null && t.getSource() instanceof org.yakindu.sct.model.sgraph.State) { error(EXITPOINTSPEC_WITH_TRIGGER, t, null, -1); } }
protected String getExitPointName(Transition transition) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("exit_"); stringBuilder.append(transition.getSource().getName()); int index = transition.getSource().getOutgoingTransitions().indexOf(transition); stringBuilder.append(index); return stringBuilder.toString(); }
/** * If a time trigger is defined for a transition then an event must be introduced into the * execution flow. */ @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()); }
@Check(CheckType.FAST) public void checkUnboundEntryPoints(final org.yakindu.sct.model.sgraph.State state) { if (state.isComposite()) { final List<Transition>[] transitions = STextValidationModelUtils.getEntrySpecSortedTransitions(state.getIncomingTransitions()); Map<Region, List<Entry>> regions = null; // first list contains Transitions without entry spec if (!transitions[0].isEmpty()) { regions = STextValidationModelUtils.getRegionsWithoutDefaultEntry(state.getRegions()); if (!regions.isEmpty()) { for (Transition transition : transitions[0]) { error(TRANSITION_UNBOUND_DEFAULT_ENTRY_POINT, transition, null, -1); } for (Region region : regions.keySet()) { error(REGION_UNBOUND_DEFAULT_ENTRY_POINT, region, null, -1); } } } // second list contains Transitions with entry spec if (!transitions[1].isEmpty()) { if (regions == null) { regions = STextValidationModelUtils.getRegionsWithoutDefaultEntry(state.getRegions()); } for (Transition transition : transitions[1]) { boolean hasTargetEntry = true; for (ReactionProperty property : transition.getProperties()) { if (property instanceof EntryPointSpec) { EntryPointSpec spec = (EntryPointSpec) property; String specName = "'" + spec.getEntrypoint() + "'"; for (Region region : regions.keySet()) { boolean hasEntry = false; for (Entry entry : regions.get(region)) { if (entry.getName().equals(spec.getEntrypoint())) { hasEntry = true; break; } } if (!hasEntry) { error(REGION_UNBOUND_NAMED_ENTRY_POINT + specName, region, null, -1); hasTargetEntry = false; } } if (!hasTargetEntry) { error(TRANSITION_UNBOUND_NAMED_ENTRY_POINT + specName, transition, null, -1); } } } } } } }
@Check(CheckType.FAST) public void checkTransitionPropertySpec(final Transition transition) { for (ReactionProperty property : transition.getProperties()) { if (property instanceof EntryPointSpec) { if (transition.getTarget() instanceof org.yakindu.sct.model.sgraph.State) { org.yakindu.sct.model.sgraph.State state = (org.yakindu.sct.model.sgraph.State) transition.getTarget(); if (!state.isComposite()) { warning(TRANSITION_ENTRY_SPEC_NOT_COMPOSITE, transition, null, -1); } } } else if (property instanceof ExitPointSpec) { final ExitPointSpec exitPointSpec = (ExitPointSpec) property; if (transition.getSource() instanceof org.yakindu.sct.model.sgraph.State) { org.yakindu.sct.model.sgraph.State state = (org.yakindu.sct.model.sgraph.State) transition.getSource(); if (!state.isComposite()) { warning(TRANSITION_EXIT_SPEC_NOT_COMPOSITE, transition, null, -1); } else { // Validate an exit point is continued on one transition // only. for (Transition t : state.getOutgoingTransitions()) { if (transition != t && STextValidationModelUtils.isNamedExitTransition( t, exitPointSpec.getExitpoint())) { warning(TRANSITION_EXIT_SPEC_ON_MULTIPLE_SIBLINGS, transition, null, -1); } } // Validate the state has minimally one named exit // region boolean hasExit = false; Iterator<Region> regionIter = state.getRegions().iterator(); while (regionIter.hasNext() && !hasExit) { Iterator<Exit> exitIter = STextValidationModelUtils.getExits(regionIter.next().eContents()).iterator(); while (exitIter.hasNext() && !hasExit) { Exit exit = exitIter.next(); hasExit = exitPointSpec.getExitpoint().equals(exit.getName()); } } if (!hasExit) { error(TRANSITION_NOT_EXISTING_NAMED_EXIT_POINT, transition, null, -1); } } } } } }
@Check public void checkChoiceWithoutDefaultTransition(final Choice choice) { boolean found = false; for (Transition transition : choice.getOutgoingTransitions()) { Trigger trigger = transition.getTrigger(); if (isDefault(trigger)) { found = true; } } if (!found) warning( CHOICE_ONE_OUTGOING_DEFAULT_TRANSITION, SGraphPackage.Literals.VERTEX__OUTGOING_TRANSITIONS); }
@Check public void orthogonalTransition(Transition transition) { Vertex source = transition.getSource(); Vertex target = transition.getTarget(); if ((source instanceof Synchronization) || (target instanceof Synchronization)) return; // ... the check does not apply. EObject commonAncestor = commonAncestor(source, target); if (commonAncestor instanceof CompositeElement) { error(ISSUE_TRANSITION_ORTHOGONAL, transition, null, -1); } }
@Override protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { if (!canExecute()) { throw new ExecutionException("Invalid arguments in create link command"); } if (getSource() != null && getTarget() != null) { Transition transition = SGraphFactory.eINSTANCE.createTransition(); source.getOutgoingTransitions().add(transition); transition.setSource(source); transition.setTarget(target); source.getOutgoingTransitions().add(transition); target.getIncomingTransitions().add(transition); ((CreateElementRequest) getRequest()).setNewElement(transition); } return CommandResult.newOKCommandResult(); }
@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(); LogicalOrExpression triggerCheck = (LogicalOrExpression) and.getLeftOperand(); PrimitiveValueExpression guardCheck = (PrimitiveValueExpression) and.getRightOperand(); 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 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()); }
/** The enter sequence must be called withnin incoming transitions. */ @SuppressWarnings("unused") @Test public void testFinalStateEnterSequenceCall() { Statechart sc = _createStatechart("sc"); { InterfaceScope s_scope = _createInterfaceScope("Interface", sc); VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER, s_scope); EventDefinition e1 = _createEventDefinition("e1", s_scope); Region r = _createRegion("r", sc); { State s1 = _createState("s1", r); FinalState fs = _createFinalState(r); Transition t_s1_fs = _createTransition(s1, fs); _createReactionTrigger(t_s1_fs); _createRegularEventSpec(e1, (ReactionTrigger) t_s1_fs.getTrigger()); } } ExecutionFlow flow = sequencer.transform(sc); ExecutionState _s1 = flow.getStates().get(0); assertEquals("sc.r.s1", _s1.getName()); ExecutionState _fs = flow.getStates().get(1); assertEquals("sc.r._final_", _fs.getName()); assertNull(_fs.getEntryAction()); assertNull(_fs.getExitAction()); // the transition s1 -> fs must includes the fs exit sequence call Sequence cycle = _s1.getReactSequence(); If _if = (If) SCTTestUtil.flattenSequenceStepsAsList(cycle).get(0); assertCall(_if.getThenStep(), _s1.getReactions().get(0).getEffect()); Sequence _seq = (Sequence) _s1.getReactions().get(0).getEffect(); assertCall(_seq, 1, _fs.getEnterSequences().get(0)); }
private void addExitPointSpec(Transition transition, Exit exitPoint) { EList<ReactionProperty> properties = transition.getProperties(); ExitPointSpec exitPointSpec = StextFactory.eINSTANCE.createExitPointSpec(); // A transition can only have one exit point so alter the existing for (ReactionProperty reactionProperty : properties) { if (reactionProperty instanceof ExitPointSpec) { exitPointSpec = (ExitPointSpec) reactionProperty; } } exitPointSpec.setExitpoint(exitPoint.getName()); properties.add(exitPointSpec); }
protected void createExitPoint(Edge edge, Diagram subdiagram) { Transition transition = (Transition) edge.getElement(); // create semantic exit point Region exitPointContainer = getExitPointContainer(transition); Exit exitPoint = createSemanticExitPoint(transition); // create node for exit point View exitPointContainerView = helper.getViewForSemanticElement(exitPointContainer, subdiagram); View exitPointRegionCompartment = ViewUtil.getChildBySemanticHint(exitPointContainerView, SemanticHints.REGION_COMPARTMENT); Node exitNode = ViewService.createNode( exitPointRegionCompartment, exitPoint, SemanticHints.EXIT, preferencesHint); // re-wire existing transition to new exit point Vertex oldTarget = transition.getTarget(); transition.setTarget(exitPoint); ViewService.createEdge( edge.getSource(), exitNode, transition, SemanticHints.TRANSITION, preferencesHint); // create transition from selected state to former transition target Transition exitPointTransition = SGraphFactory.eINSTANCE.createTransition(); exitPointTransition.setSource((State) subdiagram.getElement()); exitPointTransition.setTarget(oldTarget); ViewService.createEdge( getContextObject(), edge.getTarget(), exitPointTransition, SemanticHints.TRANSITION, preferencesHint); addExitPointSpec(exitPointTransition, exitPoint); }
@Check(CheckType.FAST) public void transitionsWithNoTrigger(Transition trans) { if (trans.getSource() instanceof Entry || trans.getSource() instanceof Choice || trans.getSource() instanceof Synchronization) { return; } if (trans.getSource() instanceof org.yakindu.sct.model.sgraph.State) { org.yakindu.sct.model.sgraph.State state = (org.yakindu.sct.model.sgraph.State) trans.getSource(); if (state.isComposite()) { for (Region r : state.getRegions()) { for (Vertex v : r.getVertices()) { if (v instanceof Exit) { return; } } } } } if (!STextValidationModelUtils.getExitPointSpecs(trans.getProperties()).isEmpty()) { return; } if (trans.getTrigger() == null) { warning(ISSUE_TRANSITION_WITHOUT_TRIGGER, trans, null, -1); } }
@Check public void orthogonalSynchronizedTransition(Synchronization sync) { List<Transition> incoming = sync.getIncomingTransitions(); List<List<EObject>> inAncestorsList = new ArrayList<List<EObject>>(); for (Transition trans : incoming) { inAncestorsList.add(collectAncestors(trans.getSource(), new ArrayList<EObject>())); } List<Transition> outgoing = sync.getOutgoingTransitions(); List<List<EObject>> outAncestorsList = new ArrayList<List<EObject>>(); for (Transition trans : outgoing) { outAncestorsList.add(collectAncestors(trans.getTarget(), new ArrayList<EObject>())); } Set<Transition> inOrthogonal = new HashSet<Transition>(incoming); Set<Transition> outOrthogonal = new HashSet<Transition>(outgoing); for (int i = 0; i < incoming.size(); i++) { for (int j = 0; j < outgoing.size(); j++) { EObject commonAncestor = findCommonAncestor(inAncestorsList.get(i), outAncestorsList.get(j)); if (commonAncestor instanceof Region) { inOrthogonal.remove(incoming.get(i)); outOrthogonal.remove(outgoing.get(j)); } } } for (Transition trans : inOrthogonal) { error(ISSUE_SYNCHRONIZATION_SOURCE_STATES_NOT_WITHIN_SAME_PARENTSTATE, trans, null, -1); } for (Transition trans : outOrthogonal) { error(ISSUE_SYNCHRONIZATION_TARGET_STATES_NOT_WITHIN_SAME_PARENTSTATE, trans, null, -1); } }
protected Entry createSemanticEntryPoint(Transition transition) { Region entryPointTarget = getEntryPointContainer(transition); String name = getEntryPointName(transition); Entry entryPoint = null; Iterator<Vertex> iterator = entryPointTarget.getVertices().iterator(); while (iterator.hasNext()) { Vertex next = iterator.next(); if (next instanceof Entry) { Entry current = (Entry) next; if (name.equals(current.getName())) { // Do nothing, there already exists an entry point return current; } } } entryPoint = SGraphFactory.eINSTANCE.createEntry(); entryPoint.setName(name); entryPointTarget.getVertices().add(entryPoint); Transition entryPointTransition = SGraphFactory.eINSTANCE.createTransition(); entryPointTransition.setSource(entryPoint); entryPointTransition.setTarget(transition.getTarget()); return entryPoint; }
@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()); }
public static Transition _createTransition(Vertex source, Vertex target) { Transition t = SGraphFactory.eINSTANCE.createTransition(); t.setSource(source); t.setTarget(target); return t; }
private Region getExitPointContainer(Transition transition) { // exit point container is the subdiagram's state's region which // contains the transition source EObject firstParentRegion = transition.getSource().getParentRegion(); return getOutermostParentRegion(firstParentRegion); }
private Region getEntryPointContainer(Transition transition) { // entry point container is the subdiagram's state's region which // contains the transition target EObject firstParentRegion = transition.getTarget().getParentRegion(); return getOutermostParentRegion(firstParentRegion); }
@Check(CheckType.FAST) public void initialEntryWithTransitionToContainer(Transition t) { if (t.getSource() instanceof Entry && !isChildOrSibling(t.getSource(), t.getTarget())) { error(ISSUE_INITIAL_ENTRY_WITH_TRANSITION_TO_CONTAINER, t, null, -1); } }
/** The state cycle must contain all reactions of parent states. */ @SuppressWarnings("unused") @Test public void testStateCycle_WithParent() { Statechart sc = _createStatechart("sc"); { InterfaceScope s_scope = _createInterfaceScope("Interface", sc); VariableDefinition v1 = _createVariableDefinition("v1", TYPE_INTEGER, s_scope); EventDefinition e1 = _createEventDefinition("e1", s_scope); Region r = _createRegion("r", sc); { State s1 = _createState("s1", r); { // a local reaction: "e1 / x=42;" LocalReaction lr1 = _createLocalReaction(s1, null); _createRegularEventSpec(e1, (ReactionTrigger) lr1.getTrigger()); ReactionEffect lr1_eff = _createReactionEffect(lr1); AssignmentExpression assign1 = _createVariableAssignment(v1, AssignmentOperator.ASSIGN, _createValue(42), lr1_eff); Region r_s1 = _createRegion("r", s1); { State s3 = _createState("s3", r_s1); { _createEntryAssignment(v1, s3, 2); Region r_s3 = _createRegion("r", s3); { State s4 = _createState("s4", r_s3); _createEntryAssignment(v1, s4, 3); State s5 = _createState("s5", r_s3); } } } } State s2 = _createState("s2", r); { Region r_s1 = _createRegion("r", s2); { _createState("s6", r_s1); } } } Transition t_s4_s5 = _createTransition(findState(sc, "s4"), findState(sc, "s5")); _createReactionTrigger(t_s4_s5); _createRegularEventSpec(e1, (ReactionTrigger) t_s4_s5.getTrigger()); Transition t_s3_s6 = _createTransition(findState(sc, "s3"), findState(sc, "s6")); _createReactionTrigger(t_s3_s6); _createRegularEventSpec(e1, (ReactionTrigger) t_s3_s6.getTrigger()); } ExecutionFlow flow = sequencer.transform(sc); ExecutionState _s1 = flow.getStates().get(0); assertEquals("sc.r.s1", _s1.getName()); ExecutionState _s3 = flow.getStates().get(1); assertEquals("sc.r.s1.r.s3", _s3.getName()); ExecutionState _s4 = flow.getStates().get(2); assertEquals("sc.r.s1.r.s3.r.s4", _s4.getName()); ExecutionState _s6 = flow.getStates().get(5); assertEquals("sc.r.s2.r.s6", _s6.getName()); Sequence cycle = _s4.getReactSequence(); Sequence _seq = (Sequence) cycle.getSteps().get(0); // first entry is the s1 local reaction List<Step> steps = SCTTestUtil.flattenSequenceStepsAsList(_seq); If _if = (If) steps.get(0); assertCall(_if.getThenStep(), _s1.getReactions().get(0).getEffect()); // second entry is the s3 cycle with the transition reaction _if = (If) steps.get(1); assertCall(_if.getThenStep(), _s3.getReactions().get(0).getEffect()); assertTrue(_s3.getReactions().get(0).isTransition()); // third is the s4 cycle with the transition reaction _seq = (Sequence) _if.getElseStep(); cycle = (Sequence) _seq.getSteps().get(0); _if = (If) cycle.getSteps().get(0); assertCall(_if.getThenStep(), _s4.getReactions().get(0).getEffect()); assertTrue(_s4.getReactions().get(0).isTransition()); assertNull(_if.getElseStep()); assertEquals(1, cycle.getSteps().size()); }