Просмотр исходного кода

fixed #1075: Validate that top level region exits are not allowed

terfloth@itemis.de 11 лет назад
Родитель
Сommit
31a598f43a

+ 49 - 10
plugins/org.yakindu.sct.model.sgraph/src/org/yakindu/sct/model/sgraph/validation/SGraphJavaValidator.java

@@ -27,8 +27,10 @@ import org.yakindu.sct.model.sgraph.Choice;
 import org.yakindu.sct.model.sgraph.CompositeElement;
 import org.yakindu.sct.model.sgraph.Entry;
 import org.yakindu.sct.model.sgraph.EntryKind;
+import org.yakindu.sct.model.sgraph.Exit;
 import org.yakindu.sct.model.sgraph.FinalState;
 import org.yakindu.sct.model.sgraph.Region;
+import org.yakindu.sct.model.sgraph.Statechart;
 import org.yakindu.sct.model.sgraph.Synchronization;
 import org.yakindu.sct.model.sgraph.Transition;
 import org.yakindu.sct.model.sgraph.Vertex;
@@ -59,6 +61,9 @@ public class SGraphJavaValidator extends AbstractDeclarativeValidator {
 	public static final String ISSUE_INITIAL_ENTRY_WITHOUT_OUT_TRANS = "Initial entry should have a single outgoing transition";
 	public static final String ISSUE_ENTRY_WITH_MULTIPLE_OUT_TRANS = "Entries must not have more than one outgoing transition";
 	public static final String ISSUE_ENTRY_WITH_TRIGGER = "Outgoing Transitions from Entries can not have a Trigger or Guard.";
+	public static final String ISSUE_EXIT_WITH_OUT_TRANS = "Exit node should have no outgoing transition.";
+	public static final String ISSUE_EXIT_WITHOUT_IN_TRANS = "Exit node should have at least one incoming transition";
+	public static final String ISSUE_EXIT_ON_STATECHART = "Exit node in top level region not supported - use final states instaed.";
 	public static final String ISSUE_CHOICE_WITHOUT_OUTGOING_TRANSITION = "A choice must have at least one outgoing transition.";
 	public static final String ISSUE_REGION_CANT_BE_ENTERED_USING_SHALLOW_HISTORY = "The region can't be entered using the shallow history. Add an entry node.";
 	public static final String ISSUE_SUBMACHINE_UNRESOLVABLE = "Referenced Substatemachine '%s'does not exist!";
@@ -128,16 +133,9 @@ public class SGraphJavaValidator extends AbstractDeclarativeValidator {
 	 * Calculates all predecessor states
 	 */
 
-	@Check(CheckType.FAST)
-	public void incomingTransitionCount(Vertex vertex) {
-		if (vertex.getIncomingTransitions().size() > 0 && vertex instanceof Entry
-				&& ((Entry) vertex).getKind().equals(EntryKind.INITIAL)) {
-			warning(ISSUE_INITIAL_ENTRY_WITH_IN_TRANS, vertex, null, -1);
-		}
-	}
 
 	@Check(CheckType.FAST)
-	public void outgoingTransitionCount(FinalState finalState) {
+	public void finalStateWithOutgoingTransition(FinalState finalState) {
 		if ((finalState.getOutgoingTransitions().size() > 0)) {
 			warning(ISSUE_FINAL_STATE_OUTGOING_TRANSITION, finalState, null, -1);
 		}
@@ -151,7 +149,7 @@ public class SGraphJavaValidator extends AbstractDeclarativeValidator {
 	}
 
 	@Check(CheckType.FAST)
-	public void outgoingTransitionCount(Choice choice) {
+	public void choiceWithoutOutgoingTransition(Choice choice) {
 		// Choice without outgoing transition
 		if (choice.getOutgoingTransitions().size() == 0) {
 			error(ISSUE_CHOICE_WITHOUT_OUTGOING_TRANSITION, choice, null, -1);
@@ -167,16 +165,57 @@ public class SGraphJavaValidator extends AbstractDeclarativeValidator {
 		}
 	}
 
+
+	@Check(CheckType.FAST)
+	public void initialEntryWithoutIncomingTransitions(Entry entry) {
+		if (entry.getIncomingTransitions().size() > 0 
+				&& entry.getKind().equals(EntryKind.INITIAL)) {
+			warning(ISSUE_INITIAL_ENTRY_WITH_IN_TRANS, entry, null, -1);
+		}
+	}
+
 	@Check(CheckType.FAST)
-	public void outgoingTransitionCount(Entry entry) {
+	public void initialEntryWithoutOutgoingTransition(Entry entry) {
 		if (entry.getOutgoingTransitions().size() == 0 && ((Entry) entry).getKind().equals(EntryKind.INITIAL)) {
 			warning(ISSUE_INITIAL_ENTRY_WITHOUT_OUT_TRANS, entry, null, -1);
 		}
+	}
+
+	@Check(CheckType.FAST)
+	public void initialEntryWithMultipleOutgoingTransition(Entry entry) {
 		if (entry.getOutgoingTransitions().size() > 1) {
 			error(ISSUE_ENTRY_WITH_MULTIPLE_OUT_TRANS, entry, null, -1);
 		}
 	}
 
+
+	@Check(CheckType.FAST)
+	public void exitWithoutIncomingTransition(Exit exit) {
+		if (exit.getIncomingTransitions().size() == 0) {
+			warning(ISSUE_EXIT_WITHOUT_IN_TRANS, exit, null, -1);
+		}
+	}
+
+	@Check(CheckType.FAST)
+	public void exitWithOutgoingTransition(Exit exit) {
+		if (exit.getOutgoingTransitions().size() > 0) {
+			error(ISSUE_EXIT_WITH_OUT_TRANS, exit, null, -1);
+		}
+	}
+
+	/**
+	 * Exit nodes in top level regions are not supported. 
+	 *  
+	 * @param exit
+	 */
+	@Check(CheckType.FAST)
+	public void exitOnStatechart(Exit exit) {
+		if (exit.getParentRegion().getComposite() instanceof Statechart) {
+			error(ISSUE_EXIT_ON_STATECHART, exit, null, -1);
+		}
+	}
+
+
 	@Check(CheckType.FAST)
 	public void synchronizationTransitionCount(Synchronization sync) {
 		if (sync.getIncomingTransitions().size() < 2 && sync.getOutgoingTransitions().size() < 2) {

+ 119 - 5
test-plugins/org.yakindu.sct.model.sgraph.test/src/org/yakindu/sct/model/sgraph/test/SGraphJavaValidationTest.java

@@ -24,12 +24,14 @@ import org.eclipse.emf.ecore.EObject;
 import org.eclipse.xtext.junit4.InjectWith;
 import org.eclipse.xtext.junit4.XtextRunner;
 import org.eclipse.xtext.validation.Check;
+import org.junit.Assume;
 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.EntryKind;
+import org.yakindu.sct.model.sgraph.Exit;
 import org.yakindu.sct.model.sgraph.FinalState;
 import org.yakindu.sct.model.sgraph.Region;
 import org.yakindu.sct.model.sgraph.SGraphFactory;
@@ -305,7 +307,7 @@ public class SGraphJavaValidationTest {
 	 * An initial entry should have no incoming transition
 	 */
 	@Test
-	public void incomingTransitionCount() {
+	public void initialEntryWithoutIncomingTransitions() {
 		prepareStateTest();
 
 		Entry entry = factory.createEntry();
@@ -337,7 +339,7 @@ public class SGraphJavaValidationTest {
 	 * An initial entry should have an outgoing transition
 	 */
 	@Test
-	public void initialEntryWithoutOutTransition() {
+	public void initialEntryWithoutOutgoingTransition() {
 		prepareStateTest();
 
 		Entry entry = factory.createEntry();
@@ -352,7 +354,7 @@ public class SGraphJavaValidationTest {
 	 * An entry should not have more than one outgoing transition
 	 */
 	@Test
-	public void entryMultipleOutTransition() {
+	public void initialEntryWithMultipleOutgoingTransition() {
 		prepareStateTest();
 
 		Entry entry = factory.createEntry();
@@ -378,6 +380,92 @@ public class SGraphJavaValidationTest {
 
 	}
 
+	
+	/**
+	 * An exit node should have at leat one incoming transition.
+	 */
+	@Test
+	public void exitWithoutIncomingTransition() {
+		prepareStateTest();
+		
+		Region subRegion = factory.createRegion();
+		state.getRegions().add(subRegion);
+		Exit exit = factory.createExit();
+		subRegion.getVertices().add(exit);
+		
+		assertFalse(validate(exit));
+		
+		assertWarning(diagnostics, ISSUE_EXIT_WITHOUT_IN_TRANS);
+	}
+	
+	
+	/**
+	 * An exit node must have no outgoing transitions.
+	 */
+	@Test
+	public void exitWithOutgoingTransition() {
+		prepareStateTest();
+		
+		Region subRegion = factory.createRegion();
+		state.getRegions().add(subRegion);
+		Exit exit = factory.createExit();
+		subRegion.getVertices().add(exit);
+		
+		State s = factory.createState();
+		subRegion.getVertices().add(s);
+
+		Transition t = factory.createTransition();
+		t.setSource(exit);
+		t.setTarget(s);
+
+		assertFalse(validate(exit));
+		
+		assertError(diagnostics, ISSUE_EXIT_WITH_OUT_TRANS);
+	}
+	
+	
+	/**
+	 * An exit node must not be used in top level regions.
+	 */
+	@Test
+	public void exitOnStatechart() {
+		prepareStateTest();
+		
+		Exit exit = factory.createExit();
+		region.getVertices().add(exit);
+		
+		assertFalse(validate(exit));
+		
+		assertError(diagnostics, ISSUE_EXIT_ON_STATECHART);
+	}
+	
+	
+	/**
+	 * Tests a scenario where no issues for an exit nodes exists.
+	 */
+	@Test
+	public void cleanExit() {
+		prepareStateTest();
+		
+		Region subRegion = factory.createRegion();
+		state.getRegions().add(subRegion);
+		Exit exit = factory.createExit();
+		subRegion.getVertices().add(exit);
+
+		State s = factory.createState();
+		subRegion.getVertices().add(s);
+
+		Transition t = factory.createTransition();
+		t.setTarget(exit);
+		t.setSource(s);
+		
+		assertTrue(validate(exit));
+		assertNoIssues(diagnostics);
+	}
+	
+	
+	
+	
 	@Test
 	public void disallowTrigger() {
 		prepareStateTest();
@@ -430,7 +518,7 @@ public class SGraphJavaValidationTest {
 	 * A final state should have no outgoing transitions
 	 */
 	@Test
-	public void outgoingTransitionCount() {
+	public void finalStateWithOutgoingTransition() {
 		statechart = factory.createStatechart();
 		Region region = factory.createRegion();
 		statechart.getRegions().add(region);
@@ -452,7 +540,7 @@ public class SGraphJavaValidationTest {
 	 * A choice must have at least one outgoing transition
 	 */
 	@Test
-	public void choiceOutgoingTransitions() {
+	public void choiceWithoutOutgoingTransition() {
 		statechart = factory.createStatechart();
 		Region region = factory.createRegion();
 		statechart.getRegions().add(region);
@@ -584,6 +672,32 @@ public class SGraphJavaValidationTest {
 		}
 	}
 
+	/**
+	 * checks that no two @Check method of {@link STextJavaValidator} have the same name. 
+	 * Avoiding overloaded check methods in the validator class allows to check it tests 
+	 * methods are explicilty written for all elelemnt types. It this is not checked than 
+	 * a single test implementation may satisfy the previous test for all overloaded functions. 
+	 */
+	@Test
+	public void testOverloadedCheckMethods() throws Exception {
+		Iterable<Method> methods = Lists.newArrayList(SGraphJavaValidator.class.getMethods());
+		methods = Iterables.filter(methods, new Predicate<Method>() {
+			public boolean apply(Method input) {
+				return input.getAnnotation(Check.class) != null;
+			}
+			
+		});
+		for (Method methodToCheck : methods) {
+			for (Method method : methods) {
+				if ( methodToCheck != method ) {
+					assertFalse(
+							"@Check method '" + methodToCheck + "' is overloaded.",
+							methodToCheck.getName().equals(method.getName()));
+				}
+			}
+		}
+	}
+
 	protected Transition createTransition(Vertex source, Vertex target) {
 		Transition trans = factory.createTransition();
 		trans.setSource(source);

+ 1 - 1
test-plugins/org.yakindu.sct.test.models/src/org/yakindu/sct/test/models/SCTUnitTestModels.java

@@ -42,7 +42,7 @@ public class SCTUnitTestModels extends AbstractTestModelsUtil {
 	public static final String ENTRY_CHOICE = "EntryChoice.sct";
 	public static final String EXIT_ON_SELF_TRANSITION = "ExitOnSelfTransition.sct";
 	public static final String EXIT_STATE = "ExitState.sct";
-	public static final String EXIT_STATECHART = "ExitStatechart.sct";
+	public static final String EXIT_STATECHART = "ExitStatechart.sct /* don't test currently */";
 	public static final String FEATURE_CALLS = "FeatureCalls.sct";
 	public static final String GUARD = "Guard.sct";
 	public static final String GUARDED_ENTRY = "GuardedEntry.sct";