From 80476e78abc9b9a353fdfe5c06bf9cf787a8bf5e Mon Sep 17 00:00:00 2001
From: Florian Lambers <fl462057@fh-muenster.de>
Date: Thu, 2 Dec 2021 17:45:52 +0100
Subject: [PATCH] added constraint validation to frontend, added flag setting

---
 .../Testgenerator/bpmn/data/BPMNTestcase.java |  9 +++
 .../bpmn/data/VariableValue.java              | 13 ++++
 .../migration/MigrationService.java           | 13 +++-
 .../rest/dto/BPMNTestcaseDTO.java             | 10 +++
 .../Testgenerator/rest/dto/ConstraintDTO.java | 33 ++++++++++
 .../rest/service/change/ChangeController.java | 21 ++++--
 .../service/converters/TestConverter.java     |  8 ++-
 .../rest/service/test/TestController.java     | 24 ++++++-
 .../rest/service/test/TestService.java        | 33 ++++++++--
 .../Testgenerator/utils/BPMNParseUtils.java   |  4 ++
 .../testgenerator-web/src/app/app.module.ts   |  6 +-
 .../app/components/flag/flag.component.css    |  0
 .../app/components/flag/flag.component.html   |  5 ++
 .../components/flag/flag.component.spec.ts    | 25 ++++++++
 .../src/app/components/flag/flag.component.ts | 17 +++++
 .../app/components/flow/flow.component.html   |  1 +
 .../app/components/flows/flows.component.html |  5 +-
 .../app/components/test/test.component.html   | 39 +++++++----
 .../src/app/components/test/test.component.ts | 64 +++++++++++++++++--
 .../src/app/models/bpmn-testcase.ts           |  1 +
 .../src/app/models/constraint.ts              |  4 ++
 .../src/app/models/variable-value.ts          |  2 +
 .../pipes/variable-constraints.pipe.spec.ts   |  8 +++
 .../app/pipes/variable-constraints.pipe.ts    | 21 ++++++
 24 files changed, 332 insertions(+), 34 deletions(-)
 create mode 100644 Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/dto/ConstraintDTO.java
 create mode 100644 testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.css
 create mode 100644 testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.html
 create mode 100644 testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.spec.ts
 create mode 100644 testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.ts
 create mode 100644 testgenerator-web/testgenerator-web/src/app/models/constraint.ts
 create mode 100644 testgenerator-web/testgenerator-web/src/app/pipes/variable-constraints.pipe.spec.ts
 create mode 100644 testgenerator-web/testgenerator-web/src/app/pipes/variable-constraints.pipe.ts

diff --git a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/bpmn/data/BPMNTestcase.java b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/bpmn/data/BPMNTestcase.java
index 325c885..28506a0 100644
--- a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/bpmn/data/BPMNTestcase.java
+++ b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/bpmn/data/BPMNTestcase.java
@@ -11,6 +11,7 @@ public class BPMNTestcase {
 	private List<EndCheck> endChecks;
 	private List<String> mocks;
 	private int priority;
+	private String flag;
 	
 	public BPMNTestcase() {
 		this.taskVariableList = new ArrayList<>();
@@ -71,4 +72,12 @@ public class BPMNTestcase {
 	public void setPriority(int priority) {
 		this.priority = priority;
 	}
+
+	public String getFlag() {
+		return flag;
+	}
+
+	public void setFlag(String flag) {
+		this.flag = flag;
+	}
 }
diff --git a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/bpmn/data/VariableValue.java b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/bpmn/data/VariableValue.java
index f489152..8304f03 100644
--- a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/bpmn/data/VariableValue.java
+++ b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/bpmn/data/VariableValue.java
@@ -1,10 +1,15 @@
 package de.fhmuenster.masterthesis.Testgenerator.bpmn.data;
 
+import java.util.List;
+
+import de.fhmuenster.masterthesis.Testgenerator.rest.dto.ConstraintDTO;
+
 public class VariableValue {
 	
 	private String variable;
 	private Object value;
 	private boolean required;
+	private List<ConstraintDTO> constraints;
 	
 	public VariableValue() {
 	}
@@ -37,4 +42,12 @@ public class VariableValue {
 	public void setRequired(boolean required) {
 		this.required = required;
 	}
+
+	public List<ConstraintDTO> getConstraints() {
+		return constraints;
+	}
+
+	public void setConstraints(List<ConstraintDTO> constraints) {
+		this.constraints = constraints;
+	}
 }
\ No newline at end of file
diff --git a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/migration/MigrationService.java b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/migration/MigrationService.java
index bf761de..b82650f 100644
--- a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/migration/MigrationService.java
+++ b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/migration/MigrationService.java
@@ -68,6 +68,7 @@ public class MigrationService {
 		transferResultsToCorrespondingCategory(migrationResultWrapper, activityDeleteProcessVariableActionResults);
 		
 		for(FlowChangeWrapper fcw : activityAddActionResults) {
+			if(!flowHasTests(fcw.getFlow(), newDSL)) continue;
 
 			try {
 				Flag maxFlag = Flag.NONE;
@@ -104,6 +105,7 @@ public class MigrationService {
 		}
 		
 		for(FlowChangeWrapper fcw : activityDeleteActionResults) {
+			if(!flowHasTests(fcw.getFlow(), newDSL)) continue;
 
 			try {
 				Flag maxFlag = Flag.NONE;
@@ -146,6 +148,7 @@ public class MigrationService {
 		}
 		
 		for(FlowChangeWrapper fcw : activityAddProcessVariableActionResults) {
+			if(!flowHasTests(fcw.getFlow(), newDSL)) continue;
 
 			try {
 				Flag maxFlag = Flag.NONE;
@@ -184,6 +187,7 @@ public class MigrationService {
 		}
 		
 		for(FlowChangeWrapper fcw : activityDeleteProcessVariableActionResults) {
+			if(!flowHasTests(fcw.getFlow(), newDSL)) continue;
 
 			try {
 				Flag maxFlag = Flag.NONE;
@@ -634,7 +638,7 @@ public class MigrationService {
 		}
 	}
 	
-	private Flag calcMaxFlag(Flag currentFlag, Flag newFlag) {
+	public Flag calcMaxFlag(Flag currentFlag, Flag newFlag) {
 		if (currentFlag.equals(Flag.NONE) &&
 				(newFlag.equals(Flag.GREEN) || newFlag.equals(Flag.YELLOW) || newFlag.equals(Flag.RED))) {
 			return newFlag;
@@ -731,4 +735,11 @@ public class MigrationService {
 		
 		return fcw;
 	}
+	
+	private boolean flowHasTests(Flow f, TestgeneratorDSLSerializer dsl) {
+		Flow dslFlow = dsl.getFlow(f.getName());
+		
+		
+		return dsl.getTestsForFlow(dslFlow).size() > 0;
+	}
 }
diff --git a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/dto/BPMNTestcaseDTO.java b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/dto/BPMNTestcaseDTO.java
index a5f29b5..8a669c9 100644
--- a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/dto/BPMNTestcaseDTO.java
+++ b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/dto/BPMNTestcaseDTO.java
@@ -11,6 +11,7 @@ public class BPMNTestcaseDTO {
 	private List<EndCheckDTO> endChecks;
 	private List<String> mocks;
 	private int priority;
+	private String flag;
 	
 	public BPMNTestcaseDTO() {
 		this.taskVariableList = new ArrayList<>();
@@ -63,4 +64,13 @@ public class BPMNTestcaseDTO {
 	public void setPriority(int priority) {
 		this.priority = priority;
 	}
+
+	public String getFlag() {
+		return flag;
+	}
+
+	public void setFlag(String flag) {
+		this.flag = flag;
+	}
+	
 }
diff --git a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/dto/ConstraintDTO.java b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/dto/ConstraintDTO.java
new file mode 100644
index 0000000..68c0005
--- /dev/null
+++ b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/dto/ConstraintDTO.java
@@ -0,0 +1,33 @@
+package de.fhmuenster.masterthesis.Testgenerator.rest.dto;
+
+public class ConstraintDTO {
+
+	private String key;
+	private int value;
+	
+	public ConstraintDTO() {
+		
+	}
+
+	public ConstraintDTO(String key, int value) {
+		super();
+		this.key = key;
+		this.value = value;
+	}
+
+	public String getKey() {
+		return key;
+	}
+
+	public void setKey(String key) {
+		this.key = key;
+	}
+
+	public int getValue() {
+		return value;
+	}
+
+	public void setValue(int value) {
+		this.value = value;
+	}
+}
diff --git a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/change/ChangeController.java b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/change/ChangeController.java
index c82cbe5..e5d88a4 100644
--- a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/change/ChangeController.java
+++ b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/change/ChangeController.java
@@ -7,6 +7,7 @@ import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import org.eclipse.emf.common.util.BasicEList;
@@ -31,6 +32,7 @@ import de.fhmuenster.masterthesis.Testgenerator.utils.ProjectDirectoryUtils;
 import de.fhmuenster.masterthesis.serialization.TestgeneratorDSLSerializer;
 import de.fhmuenster.masterthesis.Testgenerator.rest.service.test.TestService;
 import de.fhmuenster.masterthesis.testgeneratorDSL.Flow;
+import de.fhmuenster.masterthesis.testgeneratorDSL.StartFlowElement;
 import de.fhmuenster.masterthesis.testgeneratorDSL.Test;
 import de.fhmuenster.masterthesis.testgeneratorDSL.UserTaskFlowElement;
 import de.fhmuenster.masterthesis.testgeneratorDSL.VariableReference;
@@ -145,10 +147,21 @@ public class ChangeController {
 					//Prüfen, ob eine Prozessvariable gelöscht wurde, diese muss dann aus der Testspezifikation raus
 					int index = 0;
 					for(TaskVariables tv : bpmnTestcase.getTaskVariableList()) {
-						UserTaskFlowElement oldUserTask = (UserTaskFlowElement) oldDSL.getFlowElements(Arrays.asList(tv.getTask())).get(0);
-						List<VariableReference> oldInputVariables = oldUserTask.getInputVariables();
-						UserTaskFlowElement newUserTask = (UserTaskFlowElement) newDSL.getFlowElements(Arrays.asList(tv.getTask())).get(0);
-						List<VariableReference> newInputVariables = newUserTask.getInputVariables();
+						List<VariableReference> oldInputVariables = Collections.emptyList();
+						List<VariableReference> newInputVariables = Collections.emptyList();
+						if(oldDSL.getFlowElements(Arrays.asList(tv.getTask())).get(0) instanceof UserTaskFlowElement) {
+							UserTaskFlowElement oldUserTask = (UserTaskFlowElement) oldDSL.getFlowElements(Arrays.asList(tv.getTask())).get(0);
+							oldInputVariables = oldUserTask.getInputVariables();
+							UserTaskFlowElement newUserTask = (UserTaskFlowElement) newDSL.getFlowElements(Arrays.asList(tv.getTask())).get(0);
+							newInputVariables = newUserTask.getInputVariables();
+						}
+						if(oldDSL.getFlowElements(Arrays.asList(tv.getTask())).get(0) instanceof StartFlowElement) {
+							StartFlowElement oldStart = (StartFlowElement) oldDSL.getFlowElements(Arrays.asList(tv.getTask())).get(0);
+							oldInputVariables = oldStart.getInputVariables();
+							StartFlowElement newStart = (StartFlowElement) newDSL.getFlowElements(Arrays.asList(tv.getTask())).get(0);
+							newInputVariables = newStart.getInputVariables();
+						}
+						
 						
 						List<String> deletedInputVariables = new ArrayList<>();
 						for(VariableReference v : oldInputVariables) {
diff --git a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/converters/TestConverter.java b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/converters/TestConverter.java
index 1f4666c..9a6221f 100644
--- a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/converters/TestConverter.java
+++ b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/converters/TestConverter.java
@@ -13,6 +13,7 @@ import de.fhmuenster.masterthesis.serialization.TestgeneratorDSLObjectCreator;
 import de.fhmuenster.masterthesis.testgeneratorDSL.BooleanVariableEquals;
 import de.fhmuenster.masterthesis.testgeneratorDSL.BooleanVariableNotEquals;
 import de.fhmuenster.masterthesis.testgeneratorDSL.EndChecks;
+import de.fhmuenster.masterthesis.testgeneratorDSL.Flag;
 import de.fhmuenster.masterthesis.testgeneratorDSL.Flow;
 import de.fhmuenster.masterthesis.testgeneratorDSL.FlowElement;
 import de.fhmuenster.masterthesis.testgeneratorDSL.IntVariableEquals;
@@ -67,7 +68,11 @@ public class TestConverter {
 		
 		// @Tim, @Henning Priorität hier hinzufügen
 		int prio = testcase.getPriority();
-		return TestgeneratorDSLObjectCreator.createTest(testcase.getName(), flow, variableDeclarationsList, endCheckDeclaration, mocks, prio);
+		
+		//Flag
+		Flag flag = Flag.get(testcase.getFlag());
+		
+		return TestgeneratorDSLObjectCreator.createTest(testcase.getName(), flow, variableDeclarationsList, endCheckDeclaration, mocks, prio, flag);
 	}
 
 	public static FlowElement getFlowElement(List<FlowElement> flowElements, String name) {
@@ -110,6 +115,7 @@ public class TestConverter {
 		bpmnTestcase.setEndChecks(endCheckList);
 		bpmnTestcase.setMocks(mocks);
 		bpmnTestcase.setPriority(testcase.getPriority());
+		bpmnTestcase.setFlag(testcase.getFlag().name());
 
 		return bpmnTestcase;
 	}
diff --git a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/test/TestController.java b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/test/TestController.java
index 95c2c8f..c4fbe33 100644
--- a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/test/TestController.java
+++ b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/test/TestController.java
@@ -1,5 +1,6 @@
 package de.fhmuenster.masterthesis.Testgenerator.rest.service.test;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.springframework.beans.factory.annotation.Autowired;
@@ -14,6 +15,7 @@ import de.fhmuenster.masterthesis.Testgenerator.bpmn.data.BPMNServiceWithMocks;
 import de.fhmuenster.masterthesis.Testgenerator.bpmn.data.BPMNTestcase;
 import de.fhmuenster.masterthesis.Testgenerator.bpmn.data.VariableValue;
 import de.fhmuenster.masterthesis.Testgenerator.rest.dto.BPMNTestcaseDTO;
+import de.fhmuenster.masterthesis.Testgenerator.rest.dto.ConstraintDTO;
 import de.fhmuenster.masterthesis.Testgenerator.rest.dto.ExternalTopicWithMockDTO;
 import de.fhmuenster.masterthesis.Testgenerator.rest.dto.FlowElementEnhancedDTO;
 import de.fhmuenster.masterthesis.Testgenerator.rest.dto.FlowInfoDTO;
@@ -26,6 +28,7 @@ import de.fhmuenster.masterthesis.Testgenerator.rest.service.mock.MockService;
 import de.fhmuenster.masterthesis.Testgenerator.rest.service.project.Project;
 import de.fhmuenster.masterthesis.Testgenerator.rest.service.project.ProjectService;
 import de.fhmuenster.masterthesis.serialization.VariableProposal;
+import de.fhmuenster.masterthesis.testgeneratorDSL.Constraint;
 import de.fhmuenster.masterthesis.testgeneratorDSL.Flow;
 import de.fhmuenster.masterthesis.testgeneratorDSL.FlowElement;
 import de.fhmuenster.masterthesis.testgeneratorDSL.Loop;
@@ -114,7 +117,7 @@ public class TestController {
 	public void deleteTest(@PathVariable(required = true) Long projectId,
 			@PathVariable(required = true) String testId) {
 		Project projectForId = projectService.getProjectForId(projectId);
-
+		
 		testService.deleteTest(projectForId.getProjectDirectories(), testId);
 	}
 
@@ -144,6 +147,15 @@ public class TestController {
 						vv.setRequired(true);
 					}
 					
+					List<ConstraintDTO> constraintDTOs = new ArrayList<>();
+					for(Constraint constraint : vr.getRef().getConstraints()) {
+						ConstraintDTO constraintDTO = new ConstraintDTO();
+						constraintDTO.setKey(constraint.getKey());
+						constraintDTO.setValue(constraint.getValue());
+						constraintDTOs.add(constraintDTO);
+					}
+					vv.setConstraints(constraintDTOs);
+					
 					vrIndex++;
 				}
 			}
@@ -160,6 +172,16 @@ public class TestController {
 					else {
 						vv.setRequired(true);
 					}
+					
+					List<ConstraintDTO> constraintDTOs = new ArrayList<>();
+					for(Constraint constraint : vr.getRef().getConstraints()) {
+						ConstraintDTO constraintDTO = new ConstraintDTO();
+						constraintDTO.setKey(constraint.getKey());
+						constraintDTO.setValue(constraint.getValue());
+						constraintDTOs.add(constraintDTO);
+					}
+					vv.setConstraints(constraintDTOs);
+				
 					vrIndex++;
 				}
 			}
diff --git a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/test/TestService.java b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/test/TestService.java
index d1cf89e..388405b 100644
--- a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/test/TestService.java
+++ b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/rest/service/test/TestService.java
@@ -52,6 +52,7 @@ import de.fhmuenster.masterthesis.Testgenerator.dmn.data.DMNVariables;
 import de.fhmuenster.masterthesis.Testgenerator.embeddedform.data.EmbeddedFormDocument;
 import de.fhmuenster.masterthesis.Testgenerator.logging.LoggerProvider;
 import de.fhmuenster.masterthesis.Testgenerator.logging.TestgeneratorLogger;
+import de.fhmuenster.masterthesis.Testgenerator.migration.MigrationService;
 import de.fhmuenster.masterthesis.Testgenerator.rest.service.converters.TestConverter;
 import de.fhmuenster.masterthesis.Testgenerator.rest.service.flow.FlowService;
 import de.fhmuenster.masterthesis.Testgenerator.rest.service.mock.MockService;
@@ -65,6 +66,7 @@ import de.fhmuenster.masterthesis.serialization.VariableProposal;
 import de.fhmuenster.masterthesis.testgeneratorDSL.BPMNDiagram;
 import de.fhmuenster.masterthesis.testgeneratorDSL.Constraint;
 import de.fhmuenster.masterthesis.testgeneratorDSL.ExternalTopic;
+import de.fhmuenster.masterthesis.testgeneratorDSL.Flag;
 import de.fhmuenster.masterthesis.testgeneratorDSL.Flow;
 import de.fhmuenster.masterthesis.testgeneratorDSL.FlowElement;
 import de.fhmuenster.masterthesis.testgeneratorDSL.FlowElementReference;
@@ -94,6 +96,9 @@ public class TestService {
 	private FlowService flowService;
 	@Autowired
 	private MockService mockService;
+	
+	@Autowired
+	private MigrationService migrationService;
 
 	public TestService() {
 	}
@@ -266,6 +271,9 @@ public class TestService {
 				checkTestIdAlreadyTaken(testcase.getName(), serializer);
 			}
 			
+			//Test-Flag aktualisieren
+			testcase.setFlag("GREEN");
+			
 			Test testToDelete = getTest(testId, serializer);
 			serializer.deleteTest(testToDelete.getName());
 			addTest(testcase, serializer, projectDirectories);
@@ -286,6 +294,14 @@ public class TestService {
 		
 		Test newTest = TestConverter.getTest(testcase, flow, flowElements, variables, mocks);
 		serializer.addTest(newTest);
+		
+		//Am Ende prüfen, ob der Flow auch ein neues Flag bekommen soll
+		Flag maxFlag = Flag.NONE;
+		for(Test t : serializer.getTestsForFlow(flow)) {
+			maxFlag = migrationService.calcMaxFlag(maxFlag, t.getFlag());
+		}
+		
+		flow.setFlag(maxFlag);
 	}
 
 	public List<VariableProposal<?>> getVariableProposals(ProjectDirectories projectDirectories) {
@@ -381,9 +397,18 @@ public class TestService {
 
 		try {
 			TestgeneratorDSLSerializer serializer = new TestgeneratorDSLSerializer(testspecificationPath.toString());
+			
+			Test t = serializer.getTest(testId);
+			Flow f = t.getFlowReference().getRef();
+			int testCount = serializer.getTestsForFlow(f).size();
 
 			serializer.deleteTest(testId);
-
+			
+			//Letzter Test gelöscht?
+			if(testCount == 1) {
+				f.setFlag(Flag.NONE);
+			}
+			
 			serializer.serialize();
 		} catch (IOException e) {
 			//
@@ -429,7 +454,7 @@ public class TestService {
 			HashMap<String, List<BPMNFieldConstraint>> allConstraintsForTask = formFields.getAllTaskSpecificConstraintsForTask(flowElement.getId());
 			HashMap<String, List<Constraint>> newTaskSpecificConstraints = new HashMap<>();
 			
-			/*
+			
 			for(Variable v : startVariables) {
 				if(allConstraintsForTask.get(v.getName()) != null && !allConstraintsForTask.get(v.getName()).isEmpty()) {
 					//Constraints kopieren
@@ -460,9 +485,9 @@ public class TestService {
 					newTaskSpecificConstraints.put(v.getName(), variableConstraints);
 				}
 			}
-			*/
 			
-			return TestgeneratorDSLObjectCreator.createStartFlowElement(flowElement.getId(), startVariables);
+			
+			return TestgeneratorDSLObjectCreator.createStartFlowElement(flowElement.getId(), startVariables, newTaskSpecificConstraints);
 		} else if (flowElement instanceof EndEvent) {
 			return TestgeneratorDSLObjectCreator.createEndFlowElement(flowElement.getId());
 		} else if (flowElement instanceof Gateway) {
diff --git a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/utils/BPMNParseUtils.java b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/utils/BPMNParseUtils.java
index 83f8838..c06a941 100644
--- a/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/utils/BPMNParseUtils.java
+++ b/Testgenerator/src/main/java/de/fhmuenster/masterthesis/Testgenerator/utils/BPMNParseUtils.java
@@ -214,7 +214,9 @@ public class BPMNParseUtils {
 				}
 				
 				sv.getConstraints().addAll(constraintsToAdd);
+				constraintsToAdd.clear();
 			}
+			
 		}
 		constraintsToAdd.clear();
 		for(IntVariable iv : longVariables) {
@@ -243,7 +245,9 @@ public class BPMNParseUtils {
 				}
 				
 				iv.getConstraints().addAll(constraintsToAdd);
+				constraintsToAdd.clear();
 			}
+			
 		}
 		
 		variables.addAll(stringVariables);
diff --git a/testgenerator-web/testgenerator-web/src/app/app.module.ts b/testgenerator-web/testgenerator-web/src/app/app.module.ts
index 91eb3f1..8c0b63f 100644
--- a/testgenerator-web/testgenerator-web/src/app/app.module.ts
+++ b/testgenerator-web/testgenerator-web/src/app/app.module.ts
@@ -32,6 +32,8 @@ import { LoopComponent } from './components/loop/loop.component';
 import { UpdateProjectComponent } from './components/update-project/update-project.component';
 import { PrioritizationOverviewComponent } from './prioritization-overview/prioritization-overview.component';
 import { MigrationOverviewComponent } from './components/migration-overview/migration-overview.component';
+import { FlagComponent } from './components/flag/flag.component';
+import { VariableConstraintsPipe } from './pipes/variable-constraints.pipe';
 
 @NgModule({
   declarations: [
@@ -60,7 +62,9 @@ import { MigrationOverviewComponent } from './components/migration-overview/migr
     LoopComponent,
     UpdateProjectComponent,
     MigrationOverviewComponent,
-    PrioritizationOverviewComponent
+    PrioritizationOverviewComponent,
+    FlagComponent,
+    VariableConstraintsPipe
   ],
   imports: [
     BrowserModule,
diff --git a/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.css b/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.html b/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.html
new file mode 100644
index 0000000..e43f0cc
--- /dev/null
+++ b/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.html
@@ -0,0 +1,5 @@
+<div>
+    <span class="badge bg-danger" *ngIf="flag && flag === 'RED'">&nbsp;</span>
+    <span class="badge bg-warning" *ngIf="flag && flag === 'YELLOW'">&nbsp;</span>
+    <span class="badge bg-success" *ngIf="flag && flag === 'GREEN'">&nbsp;</span>
+</div>
\ No newline at end of file
diff --git a/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.spec.ts b/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.spec.ts
new file mode 100644
index 0000000..c6e9d0e
--- /dev/null
+++ b/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FlagComponent } from './flag.component';
+
+describe('FlagComponent', () => {
+  let component: FlagComponent;
+  let fixture: ComponentFixture<FlagComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ FlagComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(FlagComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.ts b/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.ts
new file mode 100644
index 0000000..9512cd0
--- /dev/null
+++ b/testgenerator-web/testgenerator-web/src/app/components/flag/flag.component.ts
@@ -0,0 +1,17 @@
+import { Component, Input, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-flag',
+  templateUrl: './flag.component.html',
+  styleUrls: ['./flag.component.css']
+})
+export class FlagComponent implements OnInit {
+
+  @Input('flag') flag: string;
+
+  constructor() { }
+
+  ngOnInit(): void {
+  }
+
+}
diff --git a/testgenerator-web/testgenerator-web/src/app/components/flow/flow.component.html b/testgenerator-web/testgenerator-web/src/app/components/flow/flow.component.html
index 9c3d145..9c750a4 100644
--- a/testgenerator-web/testgenerator-web/src/app/components/flow/flow.component.html
+++ b/testgenerator-web/testgenerator-web/src/app/components/flow/flow.component.html
@@ -28,6 +28,7 @@
                 <div *ngFor="let testcase of testcases; let i=index">
                     <hr *ngIf="i > 0">
                     <div class="testgen-testcase">
+                        <app-flag [flag]="testcase.flag"></app-flag>
                         <a class="testgen-testcase-name" [routerLink]="['test', testcase.name]">{{testcase.name}}</a>
                         <p *ngFor="let taskVariable of testcase.taskVariableList; let i=index">{{taskVariable |
                             taskVariable}}</p>
diff --git a/testgenerator-web/testgenerator-web/src/app/components/flows/flows.component.html b/testgenerator-web/testgenerator-web/src/app/components/flows/flows.component.html
index eddde30..9da9a69 100644
--- a/testgenerator-web/testgenerator-web/src/app/components/flows/flows.component.html
+++ b/testgenerator-web/testgenerator-web/src/app/components/flows/flows.component.html
@@ -24,10 +24,7 @@
         <div *ngFor="let flow of flowSet.flows; let i=index">
             <hr *ngIf="i > 0">
             <div class="testgen-flow">
-                <span class="badge bg-danger" *ngIf="flow.flag && flow.flag === 'RED'">&nbsp;</span>
-                <span class="badge bg-warning" *ngIf="flow.flag && flow.flag === 'YELLOW'">&nbsp;</span>
-                <span class="badge bg-success" *ngIf="flow.flag && flow.flag === 'GREEN'">&nbsp;</span>
-
+                <app-flag [flag]="flow.flag"></app-flag>
                 <h4 [ngClass]="{'testgen-flow-highlight': activeFlow.name === flow.name}" class="testgen-flow-name" i18n="flow name">{{flow.name}} - (Number of generated tests: {{flow.testCount}})</h4>
                 <p *ngIf="detailFlowVisible" class="testgen-flow-flowlist">{{flow | flow}}</p>
 
diff --git a/testgenerator-web/testgenerator-web/src/app/components/test/test.component.html b/testgenerator-web/testgenerator-web/src/app/components/test/test.component.html
index 10cd0ac..f4472ba 100644
--- a/testgenerator-web/testgenerator-web/src/app/components/test/test.component.html
+++ b/testgenerator-web/testgenerator-web/src/app/components/test/test.component.html
@@ -14,8 +14,8 @@
 
             <form [formGroup]="formGroup">
                 <div class="md-form form-group">
-                    <input mdbInput mdbValidate type="text" class="form-control" id="name" formControlName="name">
-                    <label for="name" i18n="testcase name" i18n="test name">Testcase name</label>
+                    <input mdbInput type="text" class="form-control" id="name" formControlName="name">
+                    <label for="name" i18n="testcase name" i18n="test name">Testcase name<span class="text-danger">*</span></label>
                     <p class="text-danger" *ngIf="formGroup.get('name').touched && formGroup.get('name').hasError('required')" i18n="test name required">Testcase name is required.</p>
                     <p class="text-danger" *ngIf="formGroup.get('name').hasError('testIdTaken')" i18n="test name taken">Testcase name is already taken.</p>
                 </div>
@@ -58,16 +58,31 @@
                             <div *ngFor="let variableValue of taskVariable.variableValues; let v=index">
                                 <!--String and Integer Fields-->
                                 <div class="md-form form-group" *ngIf="(dataTypes.get(variableValue.variable) == 'java.lang.Integer') || dataTypes.get(variableValue.variable) == 'java.lang.String'">
-                                    <input mdbInput mdbValidate type="number" class="form-control" id="{{variableValue.variable}}-{{i}}-{{v}}"
+                                    <input mdbInput type="number" class="form-control" id="{{variableValue.variable}}-{{i}}-{{v}}"
                                         formControlName="{{variableValue.variable}}" *ngIf="dataTypes.get(variableValue.variable) == 'java.lang.Integer'"
-                                        [required]="variableValue.required">
-                                    <input mdbInput mdbValidate type="text" class="form-control" id="{{variableValue.variable}}-{{i}}-{{v}}"
+                                        [required]="variableValue.required"
+                                        [min]="checkConstraint('min', variableValue.constraints)"
+                                        [max]="checkConstraint('max', variableValue.constraints)"
+                                        (input)="checkRange($event, variableValue.constraints)"
+                                        >
+                                    <input mdbInput type="text" class="form-control" id="{{variableValue.variable}}-{{i}}-{{v}}"
                                         formControlName="{{variableValue.variable}}" *ngIf="dataTypes.get(variableValue.variable) == 'java.lang.String'"
-                                        [required]="variableValue.required">
-                                    <label *ngIf="variableValue.required" class="text-danger" for="{{variableValue.variable}}-{{i}}-{{v}}">{{variableValue.variable}}</label>
+                                        [required]="variableValue.required"
+                                        [minlength]="checkConstraint('minlength', variableValue.constraints)"
+                                        [maxlength]="checkConstraint('maxlength', variableValue.constraints)">
+                                    
                                     <label *ngIf="!variableValue.required" for="{{variableValue.variable}}-{{i}}-{{v}}">{{variableValue.variable}}</label>
-                                    <p *ngIf="getVariableProposals(variableValue.variable).proposals.length > 0" i18n="proposals">Proposals : [{{getVariableProposals(variableValue.variable) | variableProposals}}]</p>
-                                    <p *ngIf="getVariableProposals(variableValue.variable).proposals.length == 0" i18n="no proposals">No proposals</p>
+                                    <label *ngIf="variableValue.required" for="{{variableValue.variable}}-{{i}}-{{v}}">{{variableValue.variable}}<span class="text-danger">*</span></label>
+                                    <div>
+                                        <span *ngIf="getVariableProposals(variableValue.variable).proposals.length > 0" i18n="proposals">Proposals : [{{getVariableProposals(variableValue.variable) | variableProposals}}]</span>
+                                        <span *ngIf="getVariableProposals(variableValue.variable).proposals.length == 0" i18n="no proposals">No proposals</span>
+                                        
+                                        <div class="d-inline ml-4">
+                                            <span *ngIf="variableValue.constraints.length > 0" i18n="constraints">Constraints: {{variableValue.constraints | variableConstraints }}</span>
+                                            <span *ngIf="variableValue.constraints.length == 0" i18n="no constraints">No constraints</span>
+                                        </div>
+                                    </div>
+                                    
                                 </div>
 
                                 <!--Boolean Checkboxes-->
@@ -108,9 +123,9 @@
 
                                     <!--String and Integer Fields-->
                                     <div class="md-form form-group" *ngIf="(dataTypes.get(variableValue.variable) == 'java.lang.Integer') || dataTypes.get(variableValue.variable) == 'java.lang.String'">
-                                        <input mdbInput mdbValidate type="number" class="form-control" id="{{variableValue.variable}}"
+                                        <input mdbInput type="number" class="form-control" id="{{variableValue.variable}}"
                                             formControlName="{{variableValue.variable}}" *ngIf="dataTypes.get(variableValue.variable) == 'java.lang.Integer'">
-                                        <input mdbInput mdbValidate type="text" class="form-control" id="{{variableValue.variable}}"
+                                        <input mdbInput type="text" class="form-control" id="{{variableValue.variable}}"
                                             formControlName="{{variableValue.variable}}" *ngIf="dataTypes.get(variableValue.variable) == 'java.lang.String'">
                                         <label for="{{variableValue.variable}}">{{variableValue.variable}}</label>
                                     </div>
@@ -151,7 +166,9 @@
             <div class="testgen-actionbar testgen-actionbar-right">
                 <button type="button" class="btn btn-light" [routerLink]="['../']" *ngIf="!isEdit" i18n="cancel">>Cancel</button>
                 <button type="button" class="btn btn-light" [routerLink]="['../../']" *ngIf="isEdit" i18n="cancel">Cancel</button>
+                
                 <button type="button" class="btn btn-success" (click)="save()" i18n="save testcase" [disabled]="formGroup.invalid">Save testcase</button>
+                <span *ngIf="formGroup.invalid" class="text-danger">The form is invalid. Please check the required fields and given constraints.</span>
             </div>
         </div>
     </div>
diff --git a/testgenerator-web/testgenerator-web/src/app/components/test/test.component.ts b/testgenerator-web/testgenerator-web/src/app/components/test/test.component.ts
index ec50ed8..05acd61 100644
--- a/testgenerator-web/testgenerator-web/src/app/components/test/test.component.ts
+++ b/testgenerator-web/testgenerator-web/src/app/components/test/test.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import { AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
 import { BPMNTestcase } from 'src/app/models/bpmn-testcase';
 import { Router, ActivatedRoute } from '@angular/router';
 import { TestService } from 'src/app/services/test.service';
@@ -15,13 +15,14 @@ import { ExternalTopicWithMocks } from 'src/app/models/external-topic-with-mocks
 import { BPMNFlow } from 'src/app/models/bpmn-flow';
 import { FlowService } from 'src/app/services/flow.service';
 import { FileService } from 'src/app/services/file.service';
+import { Constraint } from 'src/app/models/constraint';
 
 @Component({
   selector: 'app-test',
   templateUrl: './test.component.html',
   styleUrls: ['./test.component.css']
 })
-export class TestComponent implements OnInit {
+export class TestComponent implements OnInit, AfterViewChecked {
 
   isTestLoading: boolean;
   testcase: BPMNTestcase;
@@ -49,8 +50,10 @@ export class TestComponent implements OnInit {
   diagram: string;
   isDiagramLoading: boolean;
 
+  @ViewChild('saveButton') saveButton: HTMLButtonElement;
+
   constructor(private _fb: FormBuilder, private testService: TestService, private router: Router, private route: ActivatedRoute,
-    private flowService: FlowService, private fileService: FileService) {
+    private flowService: FlowService, private fileService: FileService, private cdRef: ChangeDetectorRef) {
     this.route.params.subscribe(params => {
       this.actualProject = params['projectId'];
       this.actualFlow = params['flowId'];
@@ -76,6 +79,12 @@ export class TestComponent implements OnInit {
     this.loadBPMNDiagram();
 
     this.isLoading = false;
+
+
+  }
+
+  ngAfterViewChecked() {
+    this.cdRef.detectChanges();
   }
 
   /**
@@ -100,16 +109,18 @@ export class TestComponent implements OnInit {
     for (let userInputs of this.flowInfo.userInputs) {
 
       if (userInputs.inputVariables.length > 0) {
+        
         let inputProposals = [];
         let valueObj = {};
         let variableList = [];
         for (let variables of userInputs.inputVariables) {
+
           inputProposals.push(this.getVariableProposals(variables.variable));
           let countVariableFrequency = this.countVariable(variables.variable, taskVariableValueList);
           let value = this.getVariableValueOrDefault(userInputs.name, variables.variable, countVariableFrequency);
           valueObj[variables.variable] = value;
           
-          let newVariable = this.createVariableValue(variables.variable, value, variables.required);
+          let newVariable = this.createVariableValue(variables.variable, value, variables.required, variables.constraints);
           variableList.push(newVariable);
         }
         
@@ -216,6 +227,8 @@ export class TestComponent implements OnInit {
       }
     } else {
       ValidationUtils.validateAllFormFields(this.formGroup);
+
+      console.log(this.formGroup);
     }
   }
 
@@ -250,11 +263,19 @@ export class TestComponent implements OnInit {
     }
   }
 
-  createVariableValue(variable: string, value: Object, required: boolean): VariableValue {
+  createVariableValue(variable: string, value: Object, required: boolean, constraints: Constraint[]): VariableValue {
+    let newConstraints = [];
+    
+    for(let i=0; i < constraints.length; i++) {
+      let newConstraint : Constraint = { key : constraints[i].key, value : constraints[i].value };
+      newConstraints.push(newConstraint);
+    }
+    
     return {
       variable: variable,
       value: value,
-      required: required
+      required: required,
+      constraints: newConstraints
     }
   }
 
@@ -280,7 +301,8 @@ export class TestComponent implements OnInit {
       taskVariableList: [],
       endChecks: [],
       mocks: [],
-      priority: 0
+      priority: 0,
+      flag: "GREEN"
     }
   }
 
@@ -520,4 +542,32 @@ export class TestComponent implements OnInit {
 
     return false;
   }
+
+  checkConstraint(key: string, constraints: Constraint[]): string {
+    for(let i=0; i < constraints.length; i++) {
+      if(constraints[i].key === key) {
+        return constraints[i].value.toString();
+      }
+    }
+
+    return null;
+  }
+
+  checkRange(event: any, constraints: Constraint[]) {
+    let min: number = parseInt(this.checkConstraint('min', constraints));
+    let max: number = parseInt(this.checkConstraint('max', constraints));
+    let value: number = event.target.value;
+
+    
+    if(min != null) {
+      if(value < min) {
+        event.target.value = min;
+      }
+    }
+    if(max != null) {
+      if(value > max) {
+        event.target.value = max;
+      }
+    }
+  }
 }
diff --git a/testgenerator-web/testgenerator-web/src/app/models/bpmn-testcase.ts b/testgenerator-web/testgenerator-web/src/app/models/bpmn-testcase.ts
index e8e6048..6554764 100644
--- a/testgenerator-web/testgenerator-web/src/app/models/bpmn-testcase.ts
+++ b/testgenerator-web/testgenerator-web/src/app/models/bpmn-testcase.ts
@@ -9,4 +9,5 @@ export interface BPMNTestcase {
     endChecks: Array<EndCheck>;
     mocks: Array<string>;
     priority: number;
+    flag: string;
 }
\ No newline at end of file
diff --git a/testgenerator-web/testgenerator-web/src/app/models/constraint.ts b/testgenerator-web/testgenerator-web/src/app/models/constraint.ts
new file mode 100644
index 0000000..b26a260
--- /dev/null
+++ b/testgenerator-web/testgenerator-web/src/app/models/constraint.ts
@@ -0,0 +1,4 @@
+export interface Constraint {
+    key: string;
+    value: number;
+}
\ No newline at end of file
diff --git a/testgenerator-web/testgenerator-web/src/app/models/variable-value.ts b/testgenerator-web/testgenerator-web/src/app/models/variable-value.ts
index cea82b9..f443be8 100644
--- a/testgenerator-web/testgenerator-web/src/app/models/variable-value.ts
+++ b/testgenerator-web/testgenerator-web/src/app/models/variable-value.ts
@@ -1,6 +1,8 @@
+import { Constraint } from "./constraint";
 
 export interface VariableValue {
     variable: string;
     value: Object;
     required: boolean;
+    constraints?: Array<Constraint>;
 }
\ No newline at end of file
diff --git a/testgenerator-web/testgenerator-web/src/app/pipes/variable-constraints.pipe.spec.ts b/testgenerator-web/testgenerator-web/src/app/pipes/variable-constraints.pipe.spec.ts
new file mode 100644
index 0000000..aafd950
--- /dev/null
+++ b/testgenerator-web/testgenerator-web/src/app/pipes/variable-constraints.pipe.spec.ts
@@ -0,0 +1,8 @@
+import { VariableConstraintsPipe } from './variable-constraints.pipe';
+
+describe('VariableConstraintsPipe', () => {
+  it('create an instance', () => {
+    const pipe = new VariableConstraintsPipe();
+    expect(pipe).toBeTruthy();
+  });
+});
diff --git a/testgenerator-web/testgenerator-web/src/app/pipes/variable-constraints.pipe.ts b/testgenerator-web/testgenerator-web/src/app/pipes/variable-constraints.pipe.ts
new file mode 100644
index 0000000..2197c4a
--- /dev/null
+++ b/testgenerator-web/testgenerator-web/src/app/pipes/variable-constraints.pipe.ts
@@ -0,0 +1,21 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { Constraint } from '../models/constraint';
+
+@Pipe({
+  name: 'variableConstraints'
+})
+export class VariableConstraintsPipe implements PipeTransform {
+
+  transform(value: Constraint[], ...args: unknown[]): string {
+    let result: string = "";
+    for(let i=0; i < value.length; i++) {
+      if(result !== "") {
+        result += ", ";
+      }
+      result += value[i].key + " : " + value[i].value;
+    }
+
+    return "[ " + result + " ]";
+  }
+
+}
-- 
GitLab