/** * Copyright (c) 2015 itemis AG. * 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: * itemis AG - initial API and implementation * */ package org.yakindu.sct.model.stext.test.validation; import static org.eclipse.xtext.EcoreUtil2.eAllOfType; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.yakindu.sct.model.sgraph.util.SGgraphUtil.firstNamed; import java.util.HashMap; import org.eclipse.xtext.junit4.InjectWith; import org.eclipse.xtext.junit4.XtextRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.yakindu.sct.model.sgraph.Choice; import org.yakindu.sct.model.sgraph.Entry; import org.yakindu.sct.model.sgraph.Exit; import org.yakindu.sct.model.sgraph.Region; import org.yakindu.sct.model.sgraph.State; import org.yakindu.sct.model.sgraph.Synchronization; import org.yakindu.sct.model.sgraph.Transition; import org.yakindu.sct.model.stext.stext.ReactionTrigger; import org.yakindu.sct.model.stext.stext.StextFactory; import org.yakindu.sct.model.stext.test.util.STextInjectorProvider; import org.yakindu.sct.model.stext.validation.STextValidationMessages; /** * @author terfloth - Initial contribution * */ @RunWith(XtextRunner.class) @InjectWith(STextInjectorProvider.class) public class TransitionsWithNoTriggerTest extends AbstractSTextValidationTest implements STextValidationMessages { private Entry entry; protected State stateA; private State stateB; private State stateC; private State stateD; private Choice choice; private State stateE; private Transition entryToStateA; private Transition stateAToStateB; private Transition stateBToStateC; private Transition stateCToStateD; private Transition choiceToStateE; private State stateBB; private Entry entryB; private Exit exitB; private Region regionB; private Transition entryBToStateBB; private Transition stateBBToExitB; @Override @Before public void setup() { super.setup(); StextFactory stextFactory = StextFactory.eINSTANCE; Region region = factory.createRegion(); entry = factory.createEntry(); stateA = factory.createState(); stateA.setName("A"); stateB = factory.createState(); stateB.setName("B"); stateC = factory.createState(); stateC.setName("C"); stateD = factory.createState(); stateD.setName("D"); choice = factory.createChoice(); stateE = factory.createState(); stateE.setName("E"); entryToStateA = createTransition(entry, stateA); stateAToStateB = createTransition(stateA, stateB); stateBToStateC = createTransition(stateB, stateC); stateCToStateD = createTransition(stateC, stateD); stateCToStateD.setSpecification("always"); ReactionTrigger triggerCToD = stextFactory.createReactionTrigger(); triggerCToD.getTriggers().add(stextFactory.createAlwaysEvent()); stateCToStateD.setTrigger(triggerCToD); choiceToStateE = createTransition(choice, stateE); stateBB = factory.createState(); stateBB.setName("BB"); entryB = factory.createEntry(); exitB = factory.createExit(); regionB = factory.createRegion(); regionB.getVertices().add(entryB); regionB.getVertices().add(stateBB); regionB.getVertices().add(exitB); stateB.getRegions().add(regionB); entryBToStateBB = createTransition(entryB, stateBB); stateBBToExitB = createTransition(stateBB, exitB); region.getVertices().add(entry); region.getVertices().add(stateA); region.getVertices().add(stateB); region.getVertices().add(stateC); region.getVertices().add(stateD); statechart.getRegions().add(region); } /** A transition from an entry to a state must have no trigger. */ @Test public void noTriggerOnTopLevelEntryToState() { assertTrue(validator.validate(entryToStateA, diagnostics, new HashMap<Object, Object>())); assertIssueCount(diagnostics, 0); } /** A transition from an entry to a state must have no trigger. */ @Test public void noTriggerOnSubStateEntryToState() { assertTrue(validator.validate(entryBToStateBB, diagnostics, new HashMap<Object, Object>())); assertIssueCount(diagnostics, 0); } /** No trigger on a transition from a choice to a state is valid. */ @Test public void noTriggerOnChoiceToState() { assertTrue(validator.validate(choiceToStateE, diagnostics, new HashMap<Object, Object>())); assertIssueCount(diagnostics, 0); } /** A transition from a state with exit may have no trigger. */ @Test public void noTriggerOnExitTransition() { assertTrue(validator.validate(stateBToStateC, diagnostics, new HashMap<Object, Object>())); assertIssueCount(diagnostics, 0); } /** A transition between two regular states (with no exit) should have a trigger. */ @Test public void missingTriggerOnStateToState() { assertTrue(validator.validate(stateAToStateB, diagnostics, new HashMap<Object, Object>())); assertIssueCount(diagnostics, 1); } /** A transition from a state to an exit should have a trigger. */ @Test public void missingTriggerOnStateToExit() { assertTrue(validator.validate(stateBBToExitB, diagnostics, new HashMap<Object, Object>())); assertIssueCount(diagnostics, 1); } /** A transition from a state to a state with a trigger must issue no warning. */ @Test public void existingTriggerOnStateToState() { assertTrue(validator.validate(stateCToStateD, diagnostics, new HashMap<Object, Object>())); assertIssueCount(diagnostics, 0); } /** * The outgoing transitions of a sync (fork / join) node must not have any * trigger part. Thus empty transitions must not have any warning. This test * case addresses a bug #75 ( * https://code.google.com/a/eclipselabs.org/p/yakindu/issues/detail?id=75 ) * . */ @Test public void noTriggerOnSyncOutgoing() { statechart = loadStatechart("ValidEmptyTransitionFromSync.sct"); Region validRegion = firstNamed(eAllOfType(statechart, Region.class), "valid"); Synchronization sync = eAllOfType(validRegion, Synchronization.class).get(0); for (Transition t : sync.getOutgoingTransitions()) { assertTrue(validate(t)); assertIssueCount(diagnostics, 0); } } /** * If a sync node has multiple incoming transitions then the transitions can omit the trigger. */ @Test public void noTriggerOnSyncIncoming() { statechart = loadStatechart("ValidEmptyTransitionFromSync.sct"); Region validRegion = firstNamed(eAllOfType(statechart, Region.class), "valid"); Synchronization sync = eAllOfType(validRegion, Synchronization.class).get(0); for (Transition t : sync.getIncomingTransitions()) { assertTrue(validate(t)); assertIssueCount(diagnostics, 0); } } /** * If a sync node has multiple incoming transitions then the transitions can omit the trigger. */ @Test public void missingTriggerOnSyncSingleIncoming() { statechart = loadStatechart("ValidEmptyTransitionFromSync.sct"); Region validRegion = firstNamed(eAllOfType(statechart, Region.class), "warning"); Synchronization sync = eAllOfType(validRegion, Synchronization.class).get(0); assertEquals(1, sync.getIncomingTransitions().size()); assertTrue(validate(sync.getIncomingTransitions().get(0))); assertIssueCount(diagnostics, 1); assertWarning(diagnostics, ISSUE_TRANSITION_WITHOUT_TRIGGER); } }