From 792e71ad6e18e5b343911448025905f64300eb26 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Wed, 26 Jun 2024 15:01:17 +0200 Subject: [PATCH 01/19] First experiment with generating Stakeholder Maps --- .../contextmapper/dsl/ContextMappingDSL.xtext | 28 ++++++- .../dsl/generator/PlantUMLGenerator.java | 7 ++ ...AbstractPlantUMLMindMapDiagramCreator.java | 61 ++++++++++++++ .../PlantUMLStakeholderMapGenerator.java | 84 +++++++++++++++++++ 4 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/AbstractPlantUMLMindMapDiagramCreator.java create mode 100644 org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index c1354245..00c0ca52 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -60,7 +60,8 @@ BoundedContext: ('knowledgeLevel' ('=')? knowledgeLevel=KnowledgeLevel)?) ('businessModel' ('=')? businessModel=STRING)? & ('evolution' ('=')? evolution=Evolution)? & - ((application = Application)? & + ((stakeholders += AbstractStakeholder)* & + (application = Application)? & (modules += SculptorModule)* & (aggregates += Aggregate)* & (domainServices += Service)*) @@ -356,6 +357,23 @@ SculptorModule : CLOSE)? ; +AbstractStakeholder: + StakeholderGroup | Stakeholder +; + +StakeholderGroup: + "StakeholderGroup" name=STRING (OPEN + (stakeholders+=Stakeholder)* + CLOSE)? +; + +Stakeholder: + "Stakeholder" name=STRING (OPEN + ("influence" ("=")? influence=INFLUENCE)? + ("interest" ("=")? interest=INTEREST)? + CLOSE)? +; + enum UpstreamRole: PUBLISHED_LANGUAGE = 'PL' | OPEN_HOST_SERVICE = 'OHS' ; @@ -404,6 +422,14 @@ enum Evolution : UNDEFINED | GENESIS | CUSTOM_BUILT | PRODUCT | COMMODITY ; +enum INFLUENCE : + HIGH | MEDIUM | LOW +; + +enum INTEREST : + HIGH | MEDIUM | LOW +; + // define terminals terminal OPEN: '{'; terminal CLOSE: '}'; diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java index d25fe678..b3c2fe5e 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java @@ -31,6 +31,7 @@ import org.contextmapper.dsl.generator.plantuml.PlantUMLBoundedContextClassDiagramCreator; import org.contextmapper.dsl.generator.plantuml.PlantUMLComponentDiagramCreator; import org.contextmapper.dsl.generator.plantuml.PlantUMLModuleClassDiagramCreator; +import org.contextmapper.dsl.generator.plantuml.PlantUMLStakeholderMapGenerator; import org.contextmapper.dsl.generator.plantuml.PlantUMLStateDiagramCreator4Aggregate; import org.contextmapper.dsl.generator.plantuml.PlantUMLStateDiagramCreator4Flow; import org.contextmapper.dsl.generator.plantuml.PlantUMLSubdomainClassDiagramCreator; @@ -96,6 +97,12 @@ protected void generateFromContextMappingModel(ContextMappingModel model, IFileS fsa.generateFile(fileName + "_BC_" + boundedContext.getName() + "_" + flow.getName() + "_StateDiagram." + PLANT_UML_FILE_EXT, new PlantUMLStateDiagramCreator4Flow().createDiagram(flow)); } + + // Stakeholder Map + if (!boundedContext.getStakeholders().isEmpty()) { + fsa.generateFile(fileName + "_BC_" + boundedContext.getName() + "_StakeholderMap." + PLANT_UML_FILE_EXT, + new PlantUMLStakeholderMapGenerator().createDiagram(boundedContext)); + } } // generate class diagrams for subdomains (that have entities) diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/AbstractPlantUMLMindMapDiagramCreator.java b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/AbstractPlantUMLMindMapDiagramCreator.java new file mode 100644 index 00000000..47523d48 --- /dev/null +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/AbstractPlantUMLMindMapDiagramCreator.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024 The Context Mapper Project Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.contextmapper.dsl.generator.plantuml; + +import org.eclipse.emf.ecore.EObject; + +public abstract class AbstractPlantUMLMindMapDiagramCreator implements PlantUMLDiagramCreator { + + protected StringBuilder sb; + + public AbstractPlantUMLMindMapDiagramCreator() { + this.sb = new StringBuilder(); + } + + @Override + public String createDiagram(T modelObject) { + printHeader(); + printDiagramContent(modelObject); + printFooter(); + return sb.toString(); + } + + /* + * Override this method to print diagram content + */ + protected abstract void printDiagramContent(T modelObject); + + protected void printHeader() { + sb.append("@startmindmap"); + linebreak(2); + } + + protected void printFooter() { + linebreak(2); + sb.append("@endmindmap"); + linebreak(); + } + + protected void linebreak() { + sb.append(System.lineSeparator()); + } + + protected void linebreak(int amount) { + for (int i = 0; i < amount; i++) + linebreak(); + } + +} diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java new file mode 100644 index 00000000..60c211b9 --- /dev/null +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java @@ -0,0 +1,84 @@ +/* + * Copyright 2024 The Context Mapper Project Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.contextmapper.dsl.generator.plantuml; + +import java.util.List; + +import org.contextmapper.dsl.contextMappingDSL.AbstractStakeholder; +import org.contextmapper.dsl.contextMappingDSL.BoundedContext; +import org.contextmapper.dsl.contextMappingDSL.Stakeholder; +import org.contextmapper.dsl.contextMappingDSL.StakeholderGroup; + +import com.google.common.collect.Lists; + +public class PlantUMLStakeholderMapGenerator extends AbstractPlantUMLMindMapDiagramCreator + implements PlantUMLDiagramCreator { + + private static final String STAR = "*"; + + private List left = Lists.newArrayList(); + private List right = Lists.newArrayList(); + + @Override + protected void printDiagramContent(final BoundedContext context) { + initData(context); + + sb.append(STAR).append(" ").append(context.getName()); + linebreak(); + printStakeholders(right); + linebreak(); + sb.append("left side"); + linebreak(); + printStakeholders(left); + } + + private void printStakeholders(final List stakeholders) { + for (AbstractStakeholder s : stakeholders) { + if (s instanceof StakeholderGroup) { + printStakeholderGroup((StakeholderGroup) s); + } else if (s instanceof Stakeholder) { + sb.append(STAR).append(STAR).append(" " + s.getName()); + linebreak(); + } + } + } + + private void printStakeholderGroup(final StakeholderGroup group) { + sb.append(STAR).append(STAR).append(" ").append(group.getName()); + linebreak(); + for (Stakeholder s : group.getStakeholders()) { + sb.append(STAR).append(STAR).append(STAR).append(" ").append(s.getName()); + linebreak(); + } + } + + private void initData(final BoundedContext context) { + left.clear(); + right.clear(); + + boolean addLeft = true; + + for (AbstractStakeholder s : context.getStakeholders()) { + if (addLeft) + left.add(s); + else + right.add(s); + + addLeft = !addLeft; + } + } + +} From 6cd68b33c65575678e000164cb8c81c26051346b Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Mon, 1 Jul 2024 13:48:10 +0200 Subject: [PATCH 02/19] Intermediate state on value modelling --- .../contextmapper/dsl/ContextMappingDSL.xtext | 55 ++++++++++++++++++- .../dsl/generator/PlantUMLGenerator.java | 12 ++-- .../PlantUMLStakeholderMapGenerator.java | 16 +++--- 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index 00c0ca52..391806f1 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -27,7 +27,9 @@ ContextMappingModel: (map = ContextMap)? & (boundedContexts += BoundedContext)* & (domains += Domain)* & - (userRequirements += UserRequirement)* + (userRequirements += UserRequirement)* & + (stakeholders += Stakeholders)* & + (valueRegisters += ValueRegister)* ) ; @@ -60,8 +62,7 @@ BoundedContext: ('knowledgeLevel' ('=')? knowledgeLevel=KnowledgeLevel)?) ('businessModel' ('=')? businessModel=STRING)? & ('evolution' ('=')? evolution=Evolution)? & - ((stakeholders += AbstractStakeholder)* & - (application = Application)? & + ((application = Application)? & (modules += SculptorModule)* & (aggregates += Aggregate)* & (domainServices += Service)*) @@ -357,6 +358,12 @@ SculptorModule : CLOSE)? ; +Stakeholders: + "Stakeholders" "of" (contexts+=[BoundedContext]) ("," contexts+=[BoundedContext])*(OPEN + (stakeholders+=AbstractStakeholder)* + CLOSE)? +; + AbstractStakeholder: StakeholderGroup | Stakeholder ; @@ -374,6 +381,36 @@ Stakeholder: CLOSE)? ; +ValueRegister: + "ValueRegister" name=ID "for" context=[BoundedContext] (OPEN + values+=ValueCluster* + CLOSE) +; + +ValueCluster: + "Value" name=ID (OPEN + ("core" ("=")? coreValue=CoreValue )? + (("demonstrator" ("=")?)? demonstrator=STRING)? + + elicitations+=ValueElicitation* + CLOSE) +; + +ValueElicitation: + 'Stakeholder' stakeholder=[Stakeholder] + 'Priority' priority=PRIORITY? + 'Impact' impact=IMPACT? + 'Consequences' consequences+=Consequence* +; + +Consequence: + ('good'|'bad'|'neutral') consequence=STRING action=Action? +; + +Action: + 'action' action=STRING type=('ACT'|'MONITOR'|'tbc') +; + enum UpstreamRole: PUBLISHED_LANGUAGE = 'PL' | OPEN_HOST_SERVICE = 'OHS' ; @@ -430,6 +467,18 @@ enum INTEREST : HIGH | MEDIUM | LOW ; +enum PRIORITY: + HIGH | MEDIUM | LOW +; + +enum IMPACT: + HIGH | MEDIUM | LOW +; + +enum CoreValue: + AUTONOMY | CARE | CONTROL | FAIRNESS | INCLUSIVENESS | INNOVATION | PERFECTION | PRIVACY | RESPECT | SUSTAINABILITY | TRANSPARENCY | TRUST +; + // define terminals terminal OPEN: '{'; terminal CLOSE: '}'; diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java index b3c2fe5e..dd5e3771 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java @@ -24,6 +24,7 @@ import org.contextmapper.dsl.contextMappingDSL.ContextMappingModel; import org.contextmapper.dsl.contextMappingDSL.Flow; import org.contextmapper.dsl.contextMappingDSL.SculptorModule; +import org.contextmapper.dsl.contextMappingDSL.Stakeholders; import org.contextmapper.dsl.contextMappingDSL.UseCase; import org.contextmapper.dsl.contextMappingDSL.UserRequirement; import org.contextmapper.dsl.generator.exception.GeneratorInputException; @@ -97,12 +98,11 @@ protected void generateFromContextMappingModel(ContextMappingModel model, IFileS fsa.generateFile(fileName + "_BC_" + boundedContext.getName() + "_" + flow.getName() + "_StateDiagram." + PLANT_UML_FILE_EXT, new PlantUMLStateDiagramCreator4Flow().createDiagram(flow)); } - - // Stakeholder Map - if (!boundedContext.getStakeholders().isEmpty()) { - fsa.generateFile(fileName + "_BC_" + boundedContext.getName() + "_StakeholderMap." + PLANT_UML_FILE_EXT, - new PlantUMLStakeholderMapGenerator().createDiagram(boundedContext)); - } + } + + for (Stakeholders stakeholders : model.getStakeholders()) { + fsa.generateFile(fileName + "_BC_" + stakeholders.getContexts().get(0).getName() + "_StakeholderMap." + + PLANT_UML_FILE_EXT, new PlantUMLStakeholderMapGenerator().createDiagram(stakeholders)); } // generate class diagrams for subdomains (that have entities) diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java index 60c211b9..789474a7 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java @@ -18,14 +18,14 @@ import java.util.List; import org.contextmapper.dsl.contextMappingDSL.AbstractStakeholder; -import org.contextmapper.dsl.contextMappingDSL.BoundedContext; import org.contextmapper.dsl.contextMappingDSL.Stakeholder; import org.contextmapper.dsl.contextMappingDSL.StakeholderGroup; +import org.contextmapper.dsl.contextMappingDSL.Stakeholders; import com.google.common.collect.Lists; -public class PlantUMLStakeholderMapGenerator extends AbstractPlantUMLMindMapDiagramCreator - implements PlantUMLDiagramCreator { +public class PlantUMLStakeholderMapGenerator extends AbstractPlantUMLMindMapDiagramCreator + implements PlantUMLDiagramCreator { private static final String STAR = "*"; @@ -33,10 +33,10 @@ public class PlantUMLStakeholderMapGenerator extends AbstractPlantUMLMindMapDiag private List right = Lists.newArrayList(); @Override - protected void printDiagramContent(final BoundedContext context) { - initData(context); + protected void printDiagramContent(final Stakeholders stakeholders) { + initData(stakeholders); - sb.append(STAR).append(" ").append(context.getName()); + sb.append(STAR).append(" ").append(stakeholders.getContexts().get(0).getName()); linebreak(); printStakeholders(right); linebreak(); @@ -65,13 +65,13 @@ private void printStakeholderGroup(final StakeholderGroup group) { } } - private void initData(final BoundedContext context) { + private void initData(final Stakeholders stakeholders) { left.clear(); right.clear(); boolean addLeft = true; - for (AbstractStakeholder s : context.getStakeholders()) { + for (AbstractStakeholder s : stakeholders.getStakeholders()) { if (addLeft) left.add(s); else From 38c8423f2f3b684a5228046b3fdfba6ac2c64f4c Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Tue, 30 Jul 2024 13:28:05 +0200 Subject: [PATCH 03/19] Fix unit test --- .../dsl/DomainDSLParsingTest.xtend | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/DomainDSLParsingTest.xtend b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/DomainDSLParsingTest.xtend index 32b87f7a..256c129e 100644 --- a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/DomainDSLParsingTest.xtend +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/DomainDSLParsingTest.xtend @@ -64,7 +64,7 @@ class DomainDSLParsingTest { BoundedContext testContext Domain Insurance { - Subdomain core + Subdomain CoreDomain Subdomain support1 Subdomain generic } @@ -79,7 +79,7 @@ class DomainDSLParsingTest { assertEquals(3, domain.subdomains.size); val subdomainNames = domain.subdomains.stream.map[name].collect(Collectors.toList); - assertTrue(subdomainNames.contains("core")); + assertTrue(subdomainNames.contains("CoreDomain")); assertTrue(subdomainNames.contains("support1")); assertTrue(subdomainNames.contains("generic")); } @@ -88,10 +88,10 @@ class DomainDSLParsingTest { def void canMapSubdomainToBoundedContexts() { // given val String dslSnippet = ''' - BoundedContext testContext implements core + BoundedContext testContext implements CoreDomain Domain Insurance { - Subdomain core { + Subdomain CoreDomain { type = CORE_DOMAIN } Subdomain support1 { @@ -108,17 +108,17 @@ class DomainDSLParsingTest { assertThatNoParsingErrorsOccurred(result); assertThatNoValidationErrorsOccurred(result); assertEquals(1, result.boundedContexts.get(0).implementedDomainParts.size); - assertEquals("core", result.boundedContexts.get(0).implementedDomainParts.get(0).name); + assertEquals("CoreDomain", result.boundedContexts.get(0).implementedDomainParts.get(0).name); } @Test def void canMapSubdomainsToBoundedContexts() { // given val String dslSnippet = ''' - BoundedContext testContext implements core, support1 + BoundedContext testContext implements CoreDomain, support1 Domain Insurance { - Subdomain core { + Subdomain CoreDomain { type = CORE_DOMAIN } Subdomain support1 { @@ -137,7 +137,7 @@ class DomainDSLParsingTest { assertEquals(2, result.boundedContexts.get(0).implementedDomainParts.size); val subdomainNames = result.boundedContexts.get(0).implementedDomainParts.stream.map[name].collect(Collectors.toList); - assertTrue(subdomainNames.contains("core")); + assertTrue(subdomainNames.contains("CoreDomain")); assertTrue(subdomainNames.contains("support1")); } @@ -162,7 +162,7 @@ class DomainDSLParsingTest { // given val String dslSnippet = ''' Domain Insurance { - Subdomain core { + Subdomain CoreDomain { type = CORE_DOMAIN domainVisionStatement = "my domain vision for this subdomain" } @@ -183,7 +183,7 @@ class DomainDSLParsingTest { BoundedContext testContext implements Insurance Domain Insurance { - Subdomain core { + Subdomain CoreDomain { type = CORE_DOMAIN } } @@ -200,10 +200,10 @@ class DomainDSLParsingTest { def void cannotImplementSubdomainAlreadyImplementedByDomain() { // given val String dslSnippet = ''' - BoundedContext testContext implements Insurance, core + BoundedContext testContext implements Insurance, CoreDomain Domain Insurance { - Subdomain core { + Subdomain CoreDomain { type = CORE_DOMAIN } } @@ -213,7 +213,7 @@ class DomainDSLParsingTest { // then assertThatNoParsingErrorsOccurred(result); validationTestHelper.assertError(result, ContextMappingDSLPackage.Literals.BOUNDED_CONTEXT, "", - String.format(ALREADY_IMPLEMENTED_SUBDOMAIN, "core", "Insurance")); + String.format(ALREADY_IMPLEMENTED_SUBDOMAIN, "CoreDomain", "Insurance")); } @Test @@ -223,7 +223,7 @@ class DomainDSLParsingTest { BoundedContext testContext implements Insurance, Banking Domain Insurance { - Subdomain core { + Subdomain CoreDomain { type = CORE_DOMAIN } } @@ -241,7 +241,7 @@ class DomainDSLParsingTest { // given val String dslSnippet = ''' Domain Insurance { - Subdomain core { + Subdomain CoreDomain { type = CORE_DOMAIN domainVisionStatement = "my domain vision for this subdomain" @@ -267,7 +267,7 @@ class DomainDSLParsingTest { // given val String dslSnippet = ''' Domain Insurance { - Subdomain core { + Subdomain CoreDomain { type = CORE_DOMAIN domainVisionStatement = "my domain vision for this subdomain" @@ -289,7 +289,7 @@ class DomainDSLParsingTest { // given val String dslSnippet = ''' Domain Insurance { - Subdomain core { + Subdomain CoreDomain { type CORE_DOMAIN domainVisionStatement "my domain vision for this subdomain" } From ef4dc0a370f85e59116fd6981e0d12947cec2c4e Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Tue, 30 Jul 2024 18:59:19 +0200 Subject: [PATCH 04/19] Grammar update (intermediate state; not working) --- .../contextmapper/dsl/ContextMappingDSL.xtext | 54 ++++++++++++++++--- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index 391806f1..ec98c252 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -383,24 +383,62 @@ Stakeholder: ValueRegister: "ValueRegister" name=ID "for" context=[BoundedContext] (OPEN - values+=ValueCluster* + valueClusters+=ValueCluster* + values+=Value* CLOSE) ; ValueCluster: + "ValueCluster" name=ID (OPEN + "core" ("=")? coreValue=CoreValue + (("demonstrator" ("=")?)? demonstrators+=STRING)* + values+=Value + elicitations+=ValueElicitation* // needed on this level? + CLOSE) +; + +Value: "Value" name=ID (OPEN - ("core" ("=")? coreValue=CoreValue )? - (("demonstrator" ("=")?)? demonstrator=STRING)? - + (("demonstrator" ("=")?)? demonstrators+=STRING)* elicitations+=ValueElicitation* CLOSE) ; ValueElicitation: - 'Stakeholder' stakeholder=[Stakeholder] - 'Priority' priority=PRIORITY? - 'Impact' impact=IMPACT? - 'Consequences' consequences+=Consequence* + 'Stakeholder' stakeholder=[Stakeholder] (OPEN + 'Priority' priority=PRIORITY? + 'Impact' impact=IMPACT? + 'Consequences' consequences+=Consequence* + CLOSE) +; + +ValueDemonstrator: + ValueEpic | ValueNarrative | ValueWeigthing | STRING +; + +ValueEpic: (OPEN + "As a" stakeholder=STRING "I value" coreValue=CoreValue "as demonstrated in" // TODO: stakeholder and value actually already defined upwards in hierarchy + ("a realization of" realizedLevel1Values+=STRING)+ + ("a reduction of" reducedLevel1Values+=STRING)+ + CLOSE) +; + +ValueNarrative: (OPEN + "When the SOI executes" feature=STRING "," + "stakeholders expect it to promote, protect or create" promotedValues=STRING ',' + "possibly degrading or prohibiting" harmedValues=STRING + "with the following externally observable and/or internally auditable behavior:" preAndPostConditions=STRING + CLOSE) +; + +// Q: ValueDemonstrator vs. ValueElicitation ? contains overlapping information ... (stakeholder, priorities, benefits and harms are not same as consequences?) + +ValueWeigthing: (OPEN + "In the context of SOI" system=STRING ',' // TODO: system already defined above (BC) + "stakeholder" stakeholder=STRING "values" value1=STRING "more than" value2=STRING // TODO references + "expecting benefits such as" benefits=STRING + "running the risk of harms such as" harms=STRING + CLOSE) ; Consequence: From 244c9f75a3b7e33660fcd25ef1ae55dd41f4bb75 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Wed, 31 Jul 2024 09:11:14 +0200 Subject: [PATCH 05/19] Fix grammer error/build --- .../contextmapper/dsl/ContextMappingDSL.xtext | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index ec98c252..43cddbc3 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -346,10 +346,10 @@ UserActivityDefaultVerb: SculptorModule : (doc=STRING)? - "Module" name=ID (OPEN - (external?="external")? - ("basePackage" "=" basePackage=JavaIdentifier )? - ("hint" "=" hint=STRING)? + 'Module' name=ID (OPEN + (external?='external')? + ('basePackage' '=' basePackage=JavaIdentifier )? + ('hint' '=' hint=STRING)? ((services+=Service) | (resources+=Resource) | (consumers+=Consumer) | @@ -358,8 +358,9 @@ SculptorModule : CLOSE)? ; + Stakeholders: - "Stakeholders" "of" (contexts+=[BoundedContext]) ("," contexts+=[BoundedContext])*(OPEN + 'Stakeholders' 'of' (contexts+=[BoundedContext]) (',' contexts+=[BoundedContext])*(OPEN (stakeholders+=AbstractStakeholder)* CLOSE)? ; @@ -369,37 +370,38 @@ AbstractStakeholder: ; StakeholderGroup: - "StakeholderGroup" name=STRING (OPEN + 'StakeholderGroup' name=STRING (OPEN (stakeholders+=Stakeholder)* CLOSE)? ; Stakeholder: - "Stakeholder" name=STRING (OPEN - ("influence" ("=")? influence=INFLUENCE)? - ("interest" ("=")? interest=INTEREST)? + 'Stakeholder' name=STRING (OPEN + ('influence' ('=')? influence=INFLUENCE)? + ('interest' ('=')? interest=INTEREST)? CLOSE)? ; ValueRegister: - "ValueRegister" name=ID "for" context=[BoundedContext] (OPEN + 'ValueRegister' name=ID 'for' context=[BoundedContext] (OPEN valueClusters+=ValueCluster* values+=Value* CLOSE) ; + ValueCluster: - "ValueCluster" name=ID (OPEN - "core" ("=")? coreValue=CoreValue - (("demonstrator" ("=")?)? demonstrators+=STRING)* + 'ValueCluster' name=ID (OPEN + 'core' ('=')? coreValue=CoreValue + (('demonstrator' ('=')?)? demonstrators+=STRING)* values+=Value - elicitations+=ValueElicitation* // needed on this level? + //elicitations+=ValueElicitation* // needed on this level? CLOSE) ; Value: - "Value" name=ID (OPEN - (("demonstrator" ("=")?)? demonstrators+=STRING)* + 'Value' name=ID (OPEN + (('demonstrator' ('=')?)? demonstrators+=STRING)* elicitations+=ValueElicitation* CLOSE) ; @@ -411,33 +413,34 @@ ValueElicitation: 'Consequences' consequences+=Consequence* CLOSE) ; - +/* ValueDemonstrator: - ValueEpic | ValueNarrative | ValueWeigthing | STRING + ValueEpic | ValueNarrative | ValueWeigthing ; +*/ ValueEpic: (OPEN - "As a" stakeholder=STRING "I value" coreValue=CoreValue "as demonstrated in" // TODO: stakeholder and value actually already defined upwards in hierarchy - ("a realization of" realizedLevel1Values+=STRING)+ - ("a reduction of" reducedLevel1Values+=STRING)+ + 'As a' stakeholder=STRING 'I value' coreValue=CoreValue 'as demonstrated in' // TODO: stakeholder and value actually already defined upwards in hierarchy + ('a realization of' realizedLevel1Values+=STRING)+ + ('a reduction of' reducedLevel1Values+=STRING)+ CLOSE) ; ValueNarrative: (OPEN - "When the SOI executes" feature=STRING "," - "stakeholders expect it to promote, protect or create" promotedValues=STRING ',' - "possibly degrading or prohibiting" harmedValues=STRING - "with the following externally observable and/or internally auditable behavior:" preAndPostConditions=STRING + 'When the SOI executes' feature=STRING ',' + 'stakeholders expect it to promote, protect or create' promotedValues=STRING ',' + 'possibly degrading or prohibiting' harmedValues=STRING + 'with the following externally observable and/or internally auditable behavior:' preAndPostConditions=STRING CLOSE) ; // Q: ValueDemonstrator vs. ValueElicitation ? contains overlapping information ... (stakeholder, priorities, benefits and harms are not same as consequences?) ValueWeigthing: (OPEN - "In the context of SOI" system=STRING ',' // TODO: system already defined above (BC) - "stakeholder" stakeholder=STRING "values" value1=STRING "more than" value2=STRING // TODO references - "expecting benefits such as" benefits=STRING - "running the risk of harms such as" harms=STRING + 'In the context of SOI' system=STRING ',' // TODO: system already defined above (BC) + 'stakeholder' stakeholder=STRING 'values' value1=STRING 'more than' value2=STRING // TODO references + 'expecting benefits such as' benefits=STRING + 'running the risk of harms such as' harms=STRING CLOSE) ; @@ -449,6 +452,7 @@ Action: 'action' action=STRING type=('ACT'|'MONITOR'|'tbc') ; + enum UpstreamRole: PUBLISHED_LANGUAGE = 'PL' | OPEN_HOST_SERVICE = 'OHS' ; From 965c29660966bcbd8f69d35f810a379c3ade607e Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Fri, 2 Aug 2024 15:18:30 +0200 Subject: [PATCH 06/19] Grammar draft (stakeholder + value modelling) --- .../contextmapper/dsl/ContextMappingDSL.xtext | 114 ++++++++++-------- 1 file changed, 67 insertions(+), 47 deletions(-) diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index 43cddbc3..4decc42f 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -310,8 +310,7 @@ UserRequirement: ; UseCase: - 'UseCase' name=ID - (OPEN + 'UseCase' name=ID (OPEN (('actor' ('=')? role=STRING)? & ('secondaryActors' ('=')? secondaryActors+=STRING ("," secondaryActors+=STRING)*)? & ('interactions' ('=')? features+=Feature ("," features+=Feature)*)? & @@ -322,8 +321,7 @@ UseCase: ; UserStory: - 'UserStory' name=ID ('split by' splittingStory=[UserStory])? - (OPEN + 'UserStory' name=ID ('split by' splittingStory=[UserStory])? (OPEN (('As a' | 'As an') role=STRING (features+=Feature)+ 'so that' benefit=STRING)? CLOSE)? ; @@ -360,8 +358,10 @@ SculptorModule : Stakeholders: - 'Stakeholders' 'of' (contexts+=[BoundedContext]) (',' contexts+=[BoundedContext])*(OPEN - (stakeholders+=AbstractStakeholder)* + 'Stakeholders' 'of' (contexts+=[BoundedContext]) (',' contexts+=[BoundedContext])* (OPEN + ( + (stakeholders += AbstractStakeholder)* + ) CLOSE)? ; @@ -371,76 +371,96 @@ AbstractStakeholder: StakeholderGroup: 'StakeholderGroup' name=STRING (OPEN - (stakeholders+=Stakeholder)* + ( + (stakeholders += Stakeholder)* + ) CLOSE)? ; Stakeholder: 'Stakeholder' name=STRING (OPEN - ('influence' ('=')? influence=INFLUENCE)? - ('interest' ('=')? interest=INTEREST)? + ( + ('influence' ('=')? influence=INFLUENCE)? & + ('interest' ('=')? interest=INTEREST)? + ) CLOSE)? ; ValueRegister: 'ValueRegister' name=ID 'for' context=[BoundedContext] (OPEN - valueClusters+=ValueCluster* - values+=Value* - CLOSE) + ( + (valueClusters += ValueCluster)* & + (values += Value)* & + (valueEpics += ValueEpic)* & + (valueNarratives += ValueNarrative)* & + (valueWeightings += ValueWeigthing)* + ) + CLOSE)? ; - ValueCluster: 'ValueCluster' name=ID (OPEN - 'core' ('=')? coreValue=CoreValue - (('demonstrator' ('=')?)? demonstrators+=STRING)* - values+=Value - //elicitations+=ValueElicitation* // needed on this level? - CLOSE) + ( + (('core' ('=')? coreValue7000 = CoreValue) | ('core' ('=')? coreValue = STRING)) & + ('demonstrator' ('=')? demonstrators += STRING)* & + (values += Value)* & + (elicitations += ValueElicitation)* + ) + CLOSE)? ; Value: 'Value' name=ID (OPEN - (('demonstrator' ('=')?)? demonstrators+=STRING)* - elicitations+=ValueElicitation* - CLOSE) + ( + (coreValue ?= 'core')? & + ('demonstrator' ('=')? demonstrators += STRING)* & + (elicitations += ValueElicitation)* + ) + CLOSE)? ; +// Q: table B.1 abbilden? if, how? + ValueElicitation: 'Stakeholder' stakeholder=[Stakeholder] (OPEN - 'Priority' priority=PRIORITY? - 'Impact' impact=IMPACT? - 'Consequences' consequences+=Consequence* - CLOSE) -; -/* -ValueDemonstrator: - ValueEpic | ValueNarrative | ValueWeigthing + ( + ('priority' priority = PRIORITY)? + ('impact' impact = IMPACT)? + ('consequences' consequences += Consequence)* + ) + CLOSE)? ; -*/ -ValueEpic: (OPEN - 'As a' stakeholder=STRING 'I value' coreValue=CoreValue 'as demonstrated in' // TODO: stakeholder and value actually already defined upwards in hierarchy - ('a realization of' realizedLevel1Values+=STRING)+ - ('a reduction of' reducedLevel1Values+=STRING)+ - CLOSE) + +ValueEpic: + 'ValueEpic' name=ID (OPEN + ( + 'As a' stakeholder=[Stakeholder] 'I value' value=STRING 'as demonstrated in' + (('realization of' realizedValues+=STRING)+ & + ('reduction of' reducedValues+=STRING)+) + ) + CLOSE)? ; -ValueNarrative: (OPEN - 'When the SOI executes' feature=STRING ',' - 'stakeholders expect it to promote, protect or create' promotedValues=STRING ',' - 'possibly degrading or prohibiting' harmedValues=STRING - 'with the following externally observable and/or internally auditable behavior:' preAndPostConditions=STRING +ValueNarrative: + 'ValueNarrative' name=ID (OPEN + ( + 'When the SOI executes' feature=STRING ',' + 'stakeholders expect it to promote, protect or create' promotedValues=STRING ',' + 'possibly degrading or prohibiting' harmedValues=STRING + 'with the following externally observable and/or internally auditable behavior:' preAndPostConditions=STRING + ) CLOSE) ; -// Q: ValueDemonstrator vs. ValueElicitation ? contains overlapping information ... (stakeholder, priorities, benefits and harms are not same as consequences?) - -ValueWeigthing: (OPEN - 'In the context of SOI' system=STRING ',' // TODO: system already defined above (BC) - 'stakeholder' stakeholder=STRING 'values' value1=STRING 'more than' value2=STRING // TODO references - 'expecting benefits such as' benefits=STRING - 'running the risk of harms such as' harms=STRING +ValueWeigthing: + 'ValueWeigthing' name=ID (OPEN + ( + 'In the context of the SOI,' + 'stakeholder' stakeholder=[Stakeholder] 'values' value1=STRING 'more than' value2=STRING + 'expecting benefits such as' benefits=STRING + 'running the risk of harms such as' harms=STRING + ) CLOSE) ; From 0ab4e19623fdef4a312772893d7e7351b851aa77 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Fri, 2 Aug 2024 16:02:04 +0200 Subject: [PATCH 07/19] Solve stakeholder referencing problem --- .../src/org/contextmapper/dsl/ContextMappingDSL.xtext | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index 4decc42f..06020e16 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -370,7 +370,7 @@ AbstractStakeholder: ; StakeholderGroup: - 'StakeholderGroup' name=STRING (OPEN + 'StakeholderGroup' name=ID (OPEN ( (stakeholders += Stakeholder)* ) @@ -378,7 +378,7 @@ StakeholderGroup: ; Stakeholder: - 'Stakeholder' name=STRING (OPEN + 'Stakeholder' name=ID (OPEN ( ('influence' ('=')? influence=INFLUENCE)? & ('interest' ('=')? interest=INTEREST)? @@ -422,7 +422,7 @@ Value: // Q: table B.1 abbilden? if, how? ValueElicitation: - 'Stakeholder' stakeholder=[Stakeholder] (OPEN + 'Stakeholder' stakeholder=[AbstractStakeholder] (OPEN ( ('priority' priority = PRIORITY)? ('impact' impact = IMPACT)? @@ -435,7 +435,7 @@ ValueElicitation: ValueEpic: 'ValueEpic' name=ID (OPEN ( - 'As a' stakeholder=[Stakeholder] 'I value' value=STRING 'as demonstrated in' + 'As a' stakeholder=[AbstractStakeholder] 'I value' value=STRING 'as demonstrated in' (('realization of' realizedValues+=STRING)+ & ('reduction of' reducedValues+=STRING)+) ) @@ -457,7 +457,7 @@ ValueWeigthing: 'ValueWeigthing' name=ID (OPEN ( 'In the context of the SOI,' - 'stakeholder' stakeholder=[Stakeholder] 'values' value1=STRING 'more than' value2=STRING + 'stakeholder' stakeholder=[AbstractStakeholder] 'values' value1=STRING 'more than' value2=STRING 'expecting benefits such as' benefits=STRING 'running the risk of harms such as' harms=STRING ) From 6151fb138626beffc706d55ff28a56e433f6cc86 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Mon, 5 Aug 2024 11:41:22 +0200 Subject: [PATCH 08/19] Enhance user story grammar for valuation --- .../src/org/contextmapper/dsl/ContextMappingDSL.xtext | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index 06020e16..33e77edd 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -322,7 +322,7 @@ UseCase: UserStory: 'UserStory' name=ID ('split by' splittingStory=[UserStory])? (OPEN - (('As a' | 'As an') role=STRING (features+=Feature)+ 'so that' benefit=STRING)? + (('As a' | 'As an') role=STRING (features+=Feature)+ 'so that' benefit=STRING (valuation=StoryValuation)?)? CLOSE)? ; @@ -338,6 +338,11 @@ StoryFeature: 'I want to' verb=(UserActivityDefaultVerb | STRING) (entityArticle='a' | entityArticle='an' | entityArticle='the')? entity=STRING ((entityAttributesPreposition='with its' | entityAttributesPreposition='with their') entityAttributes+=STRING ("," entityAttributes+=STRING)*)? ((containerEntityPreposition='in' | containerEntityPreposition='for' | containerEntityPreposition='to')(containerEntityArticle='a' | containerEntityArticle='an')? containerEntity=STRING)? ; +StoryValuation: + 'and that' promotedValues+=STRING (',' promotedValues+=STRING)* ('is' | 'are') 'promoted' (',')? + 'accepting that' harmedValues+=STRING (',' harmedValues+=STRING)* ('is' | 'are') ('reduced' | 'harmed') +; + UserActivityDefaultVerb: 'create' | 'read' | 'update' | 'delete' ; From 01d057711336d14f6f7f25f0cc2cb4a14b2ecd79 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Thu, 8 Aug 2024 10:02:14 +0200 Subject: [PATCH 09/19] Some grammar fixes + stakeholder modelling tests --- .../dsl/StakeholderDSLParsingTest.xtend | 335 ++++++++++++++++++ .../contextmapper/dsl/ContextMappingDSL.xtext | 12 +- 2 files changed, 341 insertions(+), 6 deletions(-) create mode 100644 org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend diff --git a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend new file mode 100644 index 00000000..4293c7c2 --- /dev/null +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend @@ -0,0 +1,335 @@ +/* + * Copyright 2024 The Context Mapper Project Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.contextmapper.dsl + +import com.google.inject.Inject +import org.contextmapper.dsl.contextMappingDSL.ContextMappingModel +import org.contextmapper.dsl.contextMappingDSL.INFLUENCE +import org.contextmapper.dsl.contextMappingDSL.INTEREST +import org.contextmapper.dsl.contextMappingDSL.Stakeholder +import org.contextmapper.dsl.contextMappingDSL.StakeholderGroup +import org.contextmapper.dsl.tests.ContextMappingDSLInjectorProvider +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.eclipse.xtext.testing.validation.ValidationTestHelper +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +import static org.contextmapper.dsl.util.ParsingErrorAssertions.* +import static org.junit.jupiter.api.Assertions.* + +@ExtendWith(InjectionExtension) +@InjectWith(ContextMappingDSLInjectorProvider) +class StakeholderDSLParsingTest { + @Inject + ParseHelper parseHelper + + ValidationTestHelper validationTestHelper = new ValidationTestHelper(); + + @Test + def void canDefineStakeholderContainerForBoundedContext() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.size); + assertEquals("testContext", result.stakeholders.get(0).contexts.get(0).name); + } + + @Test + def void canDefineStakeholder() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + Stakeholder TestUser + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser", result.stakeholders.get(0).stakeholders.get(0).name); + } + + @Test + def void canDefineStakeholderGroup() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + StakeholderGroup Users { + Stakeholder TestUser1 + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("Users", result.stakeholders.get(0).stakeholders.get(0).name); + assertEquals(1, (result.stakeholders.get(0).stakeholders.get(0) as StakeholderGroup).stakeholders.size); + assertEquals("TestUser1", (result.stakeholders.get(0).stakeholders.get(0) as StakeholderGroup).stakeholders.get(0).name); + } + + @Test + def void canDefineMultipleStakeholdersInGroup() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + StakeholderGroup Users { + Stakeholder TestUser1 + Stakeholder TestUser2 + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("Users", result.stakeholders.get(0).stakeholders.get(0).name); + assertEquals(2, (result.stakeholders.get(0).stakeholders.get(0) as StakeholderGroup).stakeholders.size); + assertEquals("TestUser1", (result.stakeholders.get(0).stakeholders.get(0) as StakeholderGroup).stakeholders.get(0).name); + assertEquals("TestUser2", (result.stakeholders.get(0).stakeholders.get(0) as StakeholderGroup).stakeholders.get(1).name); + } + + @Test + def void canDefineStakeholdersBesidesStakeholderGroups1() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + StakeholderGroup Users { + Stakeholder TestUser1 + + } + Stakeholder TestUser2 + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(2, result.stakeholders.get(0).stakeholders.size); + assertEquals("Users", (result.stakeholders.get(0).stakeholders.get(0) as StakeholderGroup).name); + assertEquals("TestUser2", (result.stakeholders.get(0).stakeholders.get(1) as Stakeholder).name); + } + + @Test + def void canDefineStakeholdersBesidesStakeholderGroups2() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + Stakeholder TestUser2 + StakeholderGroup Users { + Stakeholder TestUser1 + + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(2, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser2", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).name); + assertEquals("Users", (result.stakeholders.get(0).stakeholders.get(1) as StakeholderGroup).name); + } + + @Test + def void canDefineStakeholdersInfluence1() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + Stakeholder TestUser { + influence = HIGH + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).name); + assertEquals(INFLUENCE.HIGH, (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).influence); + } + + @Test + def void canDefineStakeholdersInfluence2() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + Stakeholder TestUser { + influence HIGH + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).name); + assertEquals(INFLUENCE.HIGH, (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).influence); + } + + @Test + def void canDefineStakeholdersInterest1() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + Stakeholder TestUser { + interest = HIGH + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).name); + assertEquals(INTEREST.HIGH, (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).interest); + } + + @Test + def void canDefineStakeholdersInterest2() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + Stakeholder TestUser { + interest HIGH + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).name); + assertEquals(INTEREST.HIGH, (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).interest); + } + + @Test + def void canDefineStakeholdersInfluenceAndInterest1() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + Stakeholder TestUser { + influence HIGH + interest LOW + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).name); + assertEquals(INFLUENCE.HIGH, (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).influence); + assertEquals(INTEREST.LOW, (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).interest); + } + + @Test + def void canDefineStakeholdersInfluenceAndInterest2() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + Stakeholder TestUser { + interest LOW + influence HIGH + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).name); + assertEquals(INTEREST.LOW, (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).interest); + assertEquals(INFLUENCE.HIGH, (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).influence); + } + +} diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index 33e77edd..6c380cc5 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -392,7 +392,7 @@ Stakeholder: ; ValueRegister: - 'ValueRegister' name=ID 'for' context=[BoundedContext] (OPEN + 'ValueRegister' name=ID ('for' context=[BoundedContext])? (OPEN ( (valueClusters += ValueCluster)* & (values += Value)* & @@ -417,7 +417,7 @@ ValueCluster: Value: 'Value' name=ID (OPEN ( - (coreValue ?= 'core')? & + (coreValue ?= 'isCore')? & ('demonstrator' ('=')? demonstrators += STRING)* & (elicitations += ValueElicitation)* ) @@ -429,9 +429,9 @@ Value: ValueElicitation: 'Stakeholder' stakeholder=[AbstractStakeholder] (OPEN ( - ('priority' priority = PRIORITY)? - ('impact' impact = IMPACT)? - ('consequences' consequences += Consequence)* + ('priority' priority = PRIORITY)? & + ('impact' impact = IMPACT)? & + ('consequences' (consequences += Consequence)+)? ) CLOSE)? ; @@ -474,7 +474,7 @@ Consequence: ; Action: - 'action' action=STRING type=('ACT'|'MONITOR'|'tbc') + 'action' action=STRING type=('ACT'|'MONITOR'|STRING) ; From e676d5fa2d23c1463a7c974c6af8af42ed4db258 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Thu, 8 Aug 2024 11:59:26 +0200 Subject: [PATCH 10/19] Test value modelling --- .../dsl/StakeholderDSLParsingTest.xtend | 3 - .../dsl/ValueRegisterDSLParsingTest.xtend | 488 ++++++++++++++++++ .../contextmapper/dsl/ContextMappingDSL.xtext | 6 +- 3 files changed, 491 insertions(+), 6 deletions(-) create mode 100644 org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend diff --git a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend index 4293c7c2..2ac55239 100644 --- a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend @@ -25,7 +25,6 @@ import org.contextmapper.dsl.tests.ContextMappingDSLInjectorProvider import org.eclipse.xtext.testing.InjectWith import org.eclipse.xtext.testing.extensions.InjectionExtension import org.eclipse.xtext.testing.util.ParseHelper -import org.eclipse.xtext.testing.validation.ValidationTestHelper import org.junit.jupiter.api.Test import org.junit.jupiter.api.^extension.ExtendWith @@ -38,8 +37,6 @@ class StakeholderDSLParsingTest { @Inject ParseHelper parseHelper - ValidationTestHelper validationTestHelper = new ValidationTestHelper(); - @Test def void canDefineStakeholderContainerForBoundedContext() { // given diff --git a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend new file mode 100644 index 00000000..c94ca351 --- /dev/null +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend @@ -0,0 +1,488 @@ +/* + * Copyright 2024 The Context Mapper Project Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.contextmapper.dsl + +import com.google.inject.Inject +import org.contextmapper.dsl.contextMappingDSL.ContextMappingModel +import org.contextmapper.dsl.tests.ContextMappingDSLInjectorProvider +import org.eclipse.xtext.testing.InjectWith +import org.eclipse.xtext.testing.extensions.InjectionExtension +import org.eclipse.xtext.testing.util.ParseHelper +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.^extension.ExtendWith + +import static org.contextmapper.dsl.util.ParsingErrorAssertions.* +import static org.junit.jupiter.api.Assertions.* +import org.contextmapper.dsl.contextMappingDSL.PRIORITY +import org.contextmapper.dsl.contextMappingDSL.IMPACT + +@ExtendWith(InjectionExtension) +@InjectWith(ContextMappingDSLInjectorProvider) +class ValueRegisterDSLParsingTest { + @Inject + ParseHelper parseHelper + + @Test + def void canDefineValueRegister() { + // given + val String dslSnippet = ''' + ValueRegister TestRegister + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.size); + assertEquals("TestRegister", result.valueRegisters.get(0).name); + } + + @Test + def void canDefineValueRegisterForBoundedContext() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.size); + assertEquals("TestRegister", result.valueRegisters.get(0).name); + assertEquals("TestContext", result.valueRegisters.get(0).context.name); + } + + @Test + def void canDefineValue() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + Value Privacy + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals(false, result.valueRegisters.get(0).values.get(0).isCoreValue); + } + + @Test + def void canDefineCoreValue() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals(true, result.valueRegisters.get(0).values.get(0).isCoreValue); + } + + @Test + def void canAddDemonstratorToValue1() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("right to be alone", result.valueRegisters.get(0).values.get(0).demonstrators.get(0)); + } + + @Test + def void canAddDemonstratorToValue2() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator = "right to be alone" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("right to be alone", result.valueRegisters.get(0).values.get(0).demonstrators.get(0)); + } + + @Test + def void canAddMultipleDemonstratorsToValue() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + demonstrator "right to keep private things secret" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("right to be alone", result.valueRegisters.get(0).values.get(0).demonstrators.get(0)); + assertEquals("right to keep private things secret", result.valueRegisters.get(0).values.get(0).demonstrators.get(1)); + } + + @Test + def void canLinkValueToStakeholder() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + Stakeholders of TestContext { + Stakeholder TestUser + } + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + Stakeholder TestUser + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("TestUser", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); + } + + @Test + def void canDefineValuePriorityForStakeholder1() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + Stakeholders of TestContext { + Stakeholder TestUser + } + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + Stakeholder TestUser { + priority HIGH + } + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("TestUser", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); + assertEquals(PRIORITY.HIGH, result.valueRegisters.get(0).values.get(0).elicitations.get(0).priority); + } + + @Test + def void canDefineValuePriorityForStakeholder2() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + Stakeholders of TestContext { + Stakeholder TestUser + } + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + Stakeholder TestUser { + priority = HIGH + } + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("TestUser", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); + assertEquals(PRIORITY.HIGH, result.valueRegisters.get(0).values.get(0).elicitations.get(0).priority); + } + + @Test + def void canDefineValueImpactForStakeholder1() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + Stakeholders of TestContext { + Stakeholder TestUser + } + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + Stakeholder TestUser { + impact HIGH + } + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("TestUser", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); + assertEquals(IMPACT.HIGH, result.valueRegisters.get(0).values.get(0).elicitations.get(0).impact); + } + + @Test + def void canDefineValueImpactForStakeholder2() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + Stakeholders of TestContext { + Stakeholder TestUser + } + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + Stakeholder TestUser { + impact = HIGH + } + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("TestUser", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); + assertEquals(IMPACT.HIGH, result.valueRegisters.get(0).values.get(0).elicitations.get(0).impact); + } + + @Test + def void canDefineValuePriorityAndImpactForStakeholder1() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + Stakeholders of TestContext { + Stakeholder TestUser + } + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + Stakeholder TestUser { + priority LOW + impact HIGH + } + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("TestUser", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); + assertEquals(PRIORITY.LOW, result.valueRegisters.get(0).values.get(0).elicitations.get(0).priority); + assertEquals(IMPACT.HIGH, result.valueRegisters.get(0).values.get(0).elicitations.get(0).impact); + } + + @Test + def void canDefineValuePriorityAndImpactForStakeholder2() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + Stakeholders of TestContext { + Stakeholder TestUser + } + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + Stakeholder TestUser { + impact HIGH + priority LOW + } + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("TestUser", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); + assertEquals(IMPACT.HIGH, result.valueRegisters.get(0).values.get(0).elicitations.get(0).impact); + assertEquals(PRIORITY.LOW, result.valueRegisters.get(0).values.get(0).elicitations.get(0).priority); + } + + @Test + def void canDefineConsequencesForStakeholder() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + Stakeholders of TestContext { + Stakeholder TestUser + } + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + Stakeholder TestUser { + impact HIGH + priority LOW + consequences + good "somehow respected" + bad "but user has to provide too much information" + } + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("TestUser", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); + assertEquals(2, result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.size); + assertEquals("good", result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.get(0).type); + assertEquals("somehow respected", result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.get(0).consequence); + assertEquals("bad", result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.get(1).type); + assertEquals("but user has to provide too much information", result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.get(1).consequence); + } + + @Test + def void canDefineActionForConsequencesForStakeholder() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + Stakeholders of TestContext { + Stakeholder TestUser + } + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + Stakeholder TestUser { + impact HIGH + priority LOW + consequences + bad "but user has to provide too much information" + action "ask for less information" ACT + } + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("TestUser", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); + assertEquals(1, result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.size); + assertEquals("bad", result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.get(0).type); + assertEquals("but user has to provide too much information", result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.get(0).consequence); + assertEquals("ask for less information", result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.get(0).action.action); + assertEquals("ACT", result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.get(0).action.type); + } + +} diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index 6c380cc5..47eec191 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -429,8 +429,8 @@ Value: ValueElicitation: 'Stakeholder' stakeholder=[AbstractStakeholder] (OPEN ( - ('priority' priority = PRIORITY)? & - ('impact' impact = IMPACT)? & + ('priority' ('=')? priority = PRIORITY)? & + ('impact' ('=')? impact = IMPACT)? & ('consequences' (consequences += Consequence)+)? ) CLOSE)? @@ -470,7 +470,7 @@ ValueWeigthing: ; Consequence: - ('good'|'bad'|'neutral') consequence=STRING action=Action? + (type='good'|type='bad'|type='neutral') consequence=STRING action=Action? ; Action: From 5e6648208e0ac3959095649a327e28bbd3f1d0a2 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Thu, 8 Aug 2024 17:00:15 +0200 Subject: [PATCH 11/19] Some additional grammar requirements --- .../dsl/StakeholderDSLParsingTest.xtend | 84 +++++++++++++++++++ .../dsl/ValueRegisterDSLParsingTest.xtend | 28 +++++++ .../contextmapper/dsl/ContextMappingDSL.xtext | 7 +- 3 files changed, 116 insertions(+), 3 deletions(-) diff --git a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend index 2ac55239..81e5f56d 100644 --- a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend @@ -37,6 +37,42 @@ class StakeholderDSLParsingTest { @Inject ParseHelper parseHelper + @Test + def void canDefineStakeholderContainerWithoutContext() { + // given + val String dslSnippet = ''' + Stakeholders {} + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.size); + assertEquals(0, result.stakeholders.get(0).contexts.size); + } + + @Test + def void canDefineStakeholderWithoutContext() { + // given + val String dslSnippet = ''' + Stakeholders { + Stakeholder TestUser + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser", result.stakeholders.get(0).stakeholders.get(0).name); + } + @Test def void canDefineStakeholderContainerForBoundedContext() { // given @@ -329,4 +365,52 @@ class StakeholderDSLParsingTest { assertEquals(INFLUENCE.HIGH, (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).influence); } + @Test + def void canDefineStakeholderDescription1() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + Stakeholder TestUser { + description = "User that tests something" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).name); + assertEquals("User that tests something", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).description); + } + + @Test + def void canDefineStakeholderDescription2() { + // given + val String dslSnippet = ''' + BoundedContext testContext + + Stakeholders of testContext { + Stakeholder TestUser { + description "User that tests something" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.stakeholders.get(0).stakeholders.size); + assertEquals("TestUser", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).name); + assertEquals("User that tests something", (result.stakeholders.get(0).stakeholders.get(0) as Stakeholder).description); + } + } diff --git a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend index c94ca351..bb99e805 100644 --- a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend @@ -217,6 +217,34 @@ class ValueRegisterDSLParsingTest { assertEquals("TestUser", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); } + @Test + def void canLinkValueToStakeholderGroup() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + Stakeholders of TestContext { + StakeholderGroup TestUsers + } + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + demonstrator "right to be alone" + Stakeholders TestUsers + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals("TestUsers", result.valueRegisters.get(0).values.get(0).elicitations.get(0).stakeholder.name); + } + @Test def void canDefineValuePriorityForStakeholder1() { // given diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index 47eec191..890ed1e9 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -363,7 +363,7 @@ SculptorModule : Stakeholders: - 'Stakeholders' 'of' (contexts+=[BoundedContext]) (',' contexts+=[BoundedContext])* (OPEN + {Stakeholders} 'Stakeholders' ('of' (contexts+=[BoundedContext]) (',' contexts+=[BoundedContext])*)? (OPEN ( (stakeholders += AbstractStakeholder)* ) @@ -386,7 +386,8 @@ Stakeholder: 'Stakeholder' name=ID (OPEN ( ('influence' ('=')? influence=INFLUENCE)? & - ('interest' ('=')? interest=INTEREST)? + ('interest' ('=')? interest=INTEREST)? & + ('description' ('=')? description=STRING)? ) CLOSE)? ; @@ -427,7 +428,7 @@ Value: // Q: table B.1 abbilden? if, how? ValueElicitation: - 'Stakeholder' stakeholder=[AbstractStakeholder] (OPEN + ('Stakeholder'|'Stakeholders') stakeholder=[AbstractStakeholder] (OPEN ( ('priority' ('=')? priority = PRIORITY)? & ('impact' ('=')? impact = IMPACT)? & From 38219ea1c1a933eddf7114bc80496a19764f5f4f Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Thu, 8 Aug 2024 17:52:57 +0200 Subject: [PATCH 12/19] Fix failing test --- .../refactorings/derive-bc-from-subdomain-test-11-input.cml | 4 ++-- .../derive-bc-from-subdomain-test-11-output.cml | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/org.contextmapper.dsl.tests/integ-test-files/refactorings/derive-bc-from-subdomain-test-11-input.cml b/org.contextmapper.dsl.tests/integ-test-files/refactorings/derive-bc-from-subdomain-test-11-input.cml index 166116b8..a57da31a 100644 --- a/org.contextmapper.dsl.tests/integ-test-files/refactorings/derive-bc-from-subdomain-test-11-input.cml +++ b/org.contextmapper.dsl.tests/integ-test-files/refactorings/derive-bc-from-subdomain-test-11-input.cml @@ -3,7 +3,7 @@ Domain Insurance_Application { Entity Claim { Date date Double amountClaimed - String description + String desc - Agent agent } Entity Policy { @@ -43,7 +43,7 @@ Domain Insurance_Application { UseCase Get_paid_for_car_accident { // title actor "Claimant" // primary actor interactions - "submit" a "Claim" with its "date", "amountClaimed", "description" for a "Policy", // step 1: claimant submits claim + "submit" a "Claim" with its "date", "amountClaimed", "desc" for a "Policy", // step 1: claimant submits claim "verifyExistanceOf" "Policy" with its "startDate", "endDate" for a "Contract", // step 2: insurance company verifies that valid policy exists "assign" an "Agent" with its "personalID", "firstName", "lastName" for "Claim", // step 3: agent is assigned to claim "verify" "Policy" for a "Contract", // step 4: agent verifies all details are within policy guidelines diff --git a/org.contextmapper.dsl.tests/integ-test-files/refactorings/derive-bc-from-subdomain-test-11-output.cml b/org.contextmapper.dsl.tests/integ-test-files/refactorings/derive-bc-from-subdomain-test-11-output.cml index 08d775db..9349738f 100644 --- a/org.contextmapper.dsl.tests/integ-test-files/refactorings/derive-bc-from-subdomain-test-11-output.cml +++ b/org.contextmapper.dsl.tests/integ-test-files/refactorings/derive-bc-from-subdomain-test-11-output.cml @@ -25,7 +25,7 @@ BoundedContext ClaimsManagement implements ClaimsManagement { Entity Claim { Date date Double amountClaimed - String description + String desc String claimId key - Agent agent } @@ -59,7 +59,7 @@ Domain Insurance_Application { Entity Claim { Date date Double amountClaimed - String description + String desc - Agent agent } Entity Policy { @@ -100,7 +100,7 @@ Domain Insurance_Application { UseCase Get_paid_for_car_accident { // title actor "Claimant" // primary actor interactions - "submit" a "Claim" with its "date", "amountClaimed", "description" for a "Policy", // step 1: claimant submits claim + "submit" a "Claim" with its "date", "amountClaimed", "desc" for a "Policy", // step 1: claimant submits claim "verifyExistanceOf" "Policy" with its "startDate", "endDate" for a "Contract", // step 2: insurance company verifies that valid policy exists "assign" an "Agent" with its "personalID", "firstName", "lastName" for "Claim", // step 3: agent is assigned to claim "verify" "Policy" for a "Contract", // step 4: agent verifies all details are within policy guidelines From d789934ccdfeab3ce7c66bbb138818c34658d9a2 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Fri, 9 Aug 2024 11:25:41 +0200 Subject: [PATCH 13/19] Related and opposing value modelling --- .../dsl/ValueRegisterDSLParsingTest.xtend | 174 ++++++++++++++++++ .../contextmapper/dsl/ContextMappingDSL.xtext | 4 + 2 files changed, 178 insertions(+) diff --git a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend index bb99e805..0dee754d 100644 --- a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend @@ -28,6 +28,7 @@ import static org.contextmapper.dsl.util.ParsingErrorAssertions.* import static org.junit.jupiter.api.Assertions.* import org.contextmapper.dsl.contextMappingDSL.PRIORITY import org.contextmapper.dsl.contextMappingDSL.IMPACT +import org.contextmapper.dsl.contextMappingDSL.CoreValue @ExtendWith(InjectionExtension) @InjectWith(ContextMappingDSLInjectorProvider) @@ -189,6 +190,60 @@ class ValueRegisterDSLParsingTest { assertEquals("right to keep private things secret", result.valueRegisters.get(0).values.get(0).demonstrators.get(1)); } + @Test + def void canAddRelatedValuesToValue() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + relatedValue "Intimacy" + relatedValue "Anonymity" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals(2, result.valueRegisters.get(0).values.get(0).relatedValues.size); + assertEquals("Intimacy", result.valueRegisters.get(0).values.get(0).relatedValues.get(0)); + assertEquals("Anonymity", result.valueRegisters.get(0).values.get(0).relatedValues.get(1)); + } + + @Test + def void canAddOpposingValuesToValue() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + Value Privacy { + isCore + opposingValue "Transparency" + opposingValue "Inclusiveness" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).values.size); + assertEquals("Privacy", result.valueRegisters.get(0).values.get(0).name); + assertEquals(2, result.valueRegisters.get(0).values.get(0).opposingValues.size); + assertEquals("Transparency", result.valueRegisters.get(0).values.get(0).opposingValues.get(0)); + assertEquals("Inclusiveness", result.valueRegisters.get(0).values.get(0).opposingValues.get(1)); + } + @Test def void canLinkValueToStakeholder() { // given @@ -513,4 +568,123 @@ class ValueRegisterDSLParsingTest { assertEquals("ACT", result.valueRegisters.get(0).values.get(0).elicitations.get(0).consequences.get(0).action.type); } + @Test + def void canDefineValueClusterWithIEEE7000Core() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + ValueCluster MyTestCluster { + core AUTONOMY + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).valueClusters.size); + assertEquals("MyTestCluster", result.valueRegisters.get(0).valueClusters.get(0).name); + assertEquals(CoreValue.AUTONOMY, result.valueRegisters.get(0).valueClusters.get(0).coreValue7000); + } + + @Test + def void canDefineValueClusterWithCustomCore() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + ValueCluster MyTestCluster { + core "MyValue" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).valueClusters.size); + assertEquals("MyTestCluster", result.valueRegisters.get(0).valueClusters.get(0).name); + assertEquals("MyValue", result.valueRegisters.get(0).valueClusters.get(0).coreValue); + } + + @Test + def void canAddDemonstratorToValueCluster() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + ValueCluster Privacy { + core PRIVACY + demonstrator "right to be alone" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).valueClusters.size); + assertEquals("right to be alone", result.valueRegisters.get(0).valueClusters.get(0).demonstrators.get(0)); + } + + @Test + def void canAddRelatedValuesToValueCluster() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + ValueCluster Privacy { + core PRIVACY + relatedValue "Respect" + relatedValue "Trust" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).valueClusters.size); + assertEquals("Respect", result.valueRegisters.get(0).valueClusters.get(0).relatedValues.get(0)); + assertEquals("Trust", result.valueRegisters.get(0).valueClusters.get(0).relatedValues.get(1)); + } + + @Test + def void canAddOpposingValuesToValueCluster() { + // given + val String dslSnippet = ''' + BoundedContext TestContext + ValueRegister TestRegister for TestContext { + ValueCluster Privacy { + core PRIVACY + opposingValue "Transparency" + opposingValue "Inclusiveness" + } + } + '''; + + // when + val ContextMappingModel result = parseHelper.parse(dslSnippet); + + // then + assertThatNoParsingErrorsOccurred(result); + assertThatNoValidationErrorsOccurred(result); + assertEquals(1, result.valueRegisters.get(0).valueClusters.size); + assertEquals("Transparency", result.valueRegisters.get(0).valueClusters.get(0).opposingValues.get(0)); + assertEquals("Inclusiveness", result.valueRegisters.get(0).valueClusters.get(0).opposingValues.get(1)); + } + } diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index 890ed1e9..cebd031b 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext @@ -409,6 +409,8 @@ ValueCluster: ( (('core' ('=')? coreValue7000 = CoreValue) | ('core' ('=')? coreValue = STRING)) & ('demonstrator' ('=')? demonstrators += STRING)* & + ('relatedValue' ('=')? relatedValues += STRING)* & + ('opposingValue' ('=')? opposingValues += STRING)* & (values += Value)* & (elicitations += ValueElicitation)* ) @@ -420,6 +422,8 @@ Value: ( (coreValue ?= 'isCore')? & ('demonstrator' ('=')? demonstrators += STRING)* & + ('relatedValue' ('=')? relatedValues += STRING)* & + ('opposingValue' ('=')? opposingValues += STRING)* & (elicitations += ValueElicitation)* ) CLOSE)? From a388e4966f00f0602b4ec08516239f3ff8fdffff Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Fri, 9 Aug 2024 11:47:38 +0200 Subject: [PATCH 14/19] Trigger build again From 27d56c16e79e6523cf5254c19cabb9a0b881de7d Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Fri, 9 Aug 2024 14:03:42 +0200 Subject: [PATCH 15/19] Update CodeCov action --- .github/workflows/build_master.yml | 2 +- .github/workflows/build_standard.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_master.yml b/.github/workflows/build_master.yml index 775b58b4..b057a8a9 100644 --- a/.github/workflows/build_master.yml +++ b/.github/workflows/build_master.yml @@ -35,7 +35,7 @@ jobs: - name: Build with Gradle run: ./gradlew clean build - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4 build_eclipse: name: Build Eclipse Plugin diff --git a/.github/workflows/build_standard.yml b/.github/workflows/build_standard.yml index 04cb46ee..b7697c8d 100644 --- a/.github/workflows/build_standard.yml +++ b/.github/workflows/build_standard.yml @@ -33,7 +33,7 @@ jobs: - name: Build with Gradle run: ./gradlew clean build - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4 build_eclipse: name: Build Eclipse Plugin diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d8279580..0e80b182 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ jobs: - name: Build with Gradle run: ./gradlew clean build - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4 build_eclipse: name: Build Eclipse Plugin From dbc58e5a153ea368bbc48a96c08c3f989ff93a07 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Fri, 9 Aug 2024 14:16:33 +0200 Subject: [PATCH 16/19] Update CodeCov action --- .github/workflows/build_master.yml | 2 ++ .github/workflows/build_standard.yml | 2 ++ .github/workflows/release.yml | 2 ++ 3 files changed, 6 insertions(+) diff --git a/.github/workflows/build_master.yml b/.github/workflows/build_master.yml index b057a8a9..bedc5324 100644 --- a/.github/workflows/build_master.yml +++ b/.github/workflows/build_master.yml @@ -36,6 +36,8 @@ jobs: run: ./gradlew clean build - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} build_eclipse: name: Build Eclipse Plugin diff --git a/.github/workflows/build_standard.yml b/.github/workflows/build_standard.yml index b7697c8d..9166d96d 100644 --- a/.github/workflows/build_standard.yml +++ b/.github/workflows/build_standard.yml @@ -34,6 +34,8 @@ jobs: run: ./gradlew clean build - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} build_eclipse: name: Build Eclipse Plugin diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0e80b182..1ba6a00c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,8 @@ jobs: run: ./gradlew clean build - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} build_eclipse: name: Build Eclipse Plugin From af54df5eea31ec8975bb86d5dd485abf5a6caad6 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Fri, 9 Aug 2024 14:18:50 +0200 Subject: [PATCH 17/19] Update CodeCov action --- .github/workflows/build_master.yml | 4 ++-- .github/workflows/build_standard.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build_master.yml b/.github/workflows/build_master.yml index bedc5324..3f00f768 100644 --- a/.github/workflows/build_master.yml +++ b/.github/workflows/build_master.yml @@ -36,8 +36,8 @@ jobs: run: ./gradlew clean build - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} + with: + token: ${{ secrets.CODECOV_TOKEN }} build_eclipse: name: Build Eclipse Plugin diff --git a/.github/workflows/build_standard.yml b/.github/workflows/build_standard.yml index 9166d96d..a415c54f 100644 --- a/.github/workflows/build_standard.yml +++ b/.github/workflows/build_standard.yml @@ -34,8 +34,8 @@ jobs: run: ./gradlew clean build - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} + with: + token: ${{ secrets.CODECOV_TOKEN }} build_eclipse: name: Build Eclipse Plugin diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1ba6a00c..48efcd59 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,8 +33,8 @@ jobs: run: ./gradlew clean build - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} + with: + token: ${{ secrets.CODECOV_TOKEN }} build_eclipse: name: Build Eclipse Plugin From ed8d6df7bd19f52c7d374ba915d20180c80177b0 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Fri, 9 Aug 2024 15:39:02 +0200 Subject: [PATCH 18/19] Setup stakeholder map generator --- .../stakeholder-diagram-generation-test-1.cml | 5 + .../plantuml/PlantUMLGeneratorTest.java | 14 +++ .../dsl/generator/PlantUMLGenerator.java | 95 ++++++++++++------- .../PlantUMLStakeholderMapGenerator.java | 10 +- 4 files changed, 87 insertions(+), 37 deletions(-) create mode 100644 org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-1.cml diff --git a/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-1.cml b/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-1.cml new file mode 100644 index 00000000..7f76ca4b --- /dev/null +++ b/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-1.cml @@ -0,0 +1,5 @@ +Stakeholders { + + Stakeholder Tester + +} \ No newline at end of file diff --git a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/generators/plantuml/PlantUMLGeneratorTest.java b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/generators/plantuml/PlantUMLGeneratorTest.java index 25cc1b4d..9e86b9b5 100644 --- a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/generators/plantuml/PlantUMLGeneratorTest.java +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/generators/plantuml/PlantUMLGeneratorTest.java @@ -192,6 +192,20 @@ void canCreateSequenceDiagram4UseCaseInteractionsIfAvailable() throws IOExceptio // then assertTrue(filesystem.getGeneratedFilesSet().contains("testmodel_UseCase_Get_paid_for_car_accident_Interactions.puml")); } + + @Test + void canCreateStakeholderDiagramsIfStakeholdersAreAvailable() throws IOException { + // given + ContextMappingModel model = getOriginalResourceOfTestCML("stakeholder-diagram-generation-test-1.cml").getContextMappingModel(); + + + // when + IFileSystemAccess2Mock filesystem = new IFileSystemAccess2Mock(); + this.generator.doGenerate(new ContextMappingModelResourceMock(model, "testmodel", "cml"), filesystem, new IGeneratorContextMock()); + + // then + assertTrue(filesystem.getGeneratedFilesSet().contains("testmodel_BC_System-of-Interest_StakeholderMap-1.puml")); + } @Test void expectExceptionForEmptyResource() { diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java index dd5e3771..072a82f9 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/PlantUMLGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 The Context Mapper Project Team + * Copyright 2018-2024 The Context Mapper Project Team * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,12 +58,56 @@ protected void generateFromContextMappingModel(ContextMappingModel model, IFileS checkPreconditions(); String fileName = inputFileURI.trimFileExtension().lastSegment(); - // generate component diagram, if Context Map available - if (model.getMap() != null) - fsa.generateFile(fileName + "_ContextMap." + PLANT_UML_FILE_EXT, - new PlantUMLComponentDiagramCreator().createDiagram(model.getMap())); + generateComponentDiagramIfContextMapAvailable(model, fsa, fileName); + generateClassAndStateDiagramsForBoundedContexts(model, fsa, fileName); + generateClassDiagramsForSubdomains(fsa, fileName); + generateUseCaseDiagram(model, fsa, fileName); + generateSequenceDiagramsForUseCases(model, fsa, fileName); + generateStakeholderDiagrams(model, fsa, fileName); + } + + private void generateStakeholderDiagrams(ContextMappingModel model, IFileSystemAccess2 fsa, String fileName) { + PlantUMLStakeholderMapGenerator stakeholderDiagramGenerator = new PlantUMLStakeholderMapGenerator(); + int index = 1; + for (Stakeholders stakeholders : model.getStakeholders()) { + fsa.generateFile(fileName + "_BC_" + + stakeholderDiagramGenerator.getStakeholderDiagramContextName(stakeholders.getContexts()) + .replace(", ", "-").replace(" ", "-") + + "_StakeholderMap-" + index++ + "." + PLANT_UML_FILE_EXT, + stakeholderDiagramGenerator.createDiagram(stakeholders)); + } + } + + private void generateSequenceDiagramsForUseCases(ContextMappingModel model, IFileSystemAccess2 fsa, + String fileName) { + for (UserRequirement userRequirement : model.getUserRequirements()) { + if (userRequirement instanceof UseCase && !userRequirement.getFeatures().isEmpty()) { + fsa.generateFile( + fileName + "_UseCase_" + userRequirement.getName() + "_Interactions." + PLANT_UML_FILE_EXT, + new PlantUMLUseCaseInteractionsSequenceDiagramCreator() + .createDiagram((UseCase) userRequirement)); + } + } + } + + private void generateUseCaseDiagram(ContextMappingModel model, IFileSystemAccess2 fsa, String fileName) { + if (!model.getUserRequirements().isEmpty()) + fsa.generateFile(fileName + "_UseCases." + PLANT_UML_FILE_EXT, + new PlantUMLUseCaseDiagramCreator().createDiagram(model)); + } + + private void generateClassDiagramsForSubdomains(IFileSystemAccess2 fsa, String fileName) { + subdomainResolver.resolveAllSubdomains().stream().filter(subdomain -> !subdomain.getEntities().isEmpty()) + .forEach(subdomain -> { + fsa.generateFile(fileName + "_SD_" + subdomain.getName() + "." + PLANT_UML_FILE_EXT, + new PlantUMLSubdomainClassDiagramCreator( + subdomainResolver.resolveDomain4Subdomain(subdomain.getName()).getName()) + .createDiagram(subdomain)); + }); + } - // generate class and state diagrams for Bounded Contexts + private void generateClassAndStateDiagramsForBoundedContexts(ContextMappingModel model, IFileSystemAccess2 fsa, + String fileName) { for (BoundedContext boundedContext : model.getBoundedContexts()) { // class diagram for complete BC @@ -99,42 +143,21 @@ protected void generateFromContextMappingModel(ContextMappingModel model, IFileS + PLANT_UML_FILE_EXT, new PlantUMLStateDiagramCreator4Flow().createDiagram(flow)); } } - - for (Stakeholders stakeholders : model.getStakeholders()) { - fsa.generateFile(fileName + "_BC_" + stakeholders.getContexts().get(0).getName() + "_StakeholderMap." - + PLANT_UML_FILE_EXT, new PlantUMLStakeholderMapGenerator().createDiagram(stakeholders)); - } - - // generate class diagrams for subdomains (that have entities) - subdomainResolver.resolveAllSubdomains().stream().filter(subdomain -> !subdomain.getEntities().isEmpty()) - .forEach(subdomain -> { - fsa.generateFile(fileName + "_SD_" + subdomain.getName() + "." + PLANT_UML_FILE_EXT, - new PlantUMLSubdomainClassDiagramCreator( - subdomainResolver.resolveDomain4Subdomain(subdomain.getName()).getName()) - .createDiagram(subdomain)); - }); - - // generate Use Case diagram out of user requirements, if available - if (!model.getUserRequirements().isEmpty()) - fsa.generateFile(fileName + "_UseCases." + PLANT_UML_FILE_EXT, - new PlantUMLUseCaseDiagramCreator().createDiagram(model)); + } - // generate sequence diagrams for Use Cases with interactions - for (UserRequirement userRequirement : model.getUserRequirements()) { - if (userRequirement instanceof UseCase && !userRequirement.getFeatures().isEmpty()) { - fsa.generateFile( - fileName + "_UseCase_" + userRequirement.getName() + "_Interactions." + PLANT_UML_FILE_EXT, - new PlantUMLUseCaseInteractionsSequenceDiagramCreator() - .createDiagram((UseCase) userRequirement)); - } - } + private void generateComponentDiagramIfContextMapAvailable(ContextMappingModel model, IFileSystemAccess2 fsa, + String fileName) { + if (model.getMap() != null) + fsa.generateFile(fileName + "_ContextMap." + PLANT_UML_FILE_EXT, + new PlantUMLComponentDiagramCreator().createDiagram(model.getMap())); } private void checkPreconditions() { if (this.contextMappingModel.getMap() == null && this.contextMappingModel.getBoundedContexts().isEmpty() - && !modelHasSubdomainWithEntities() && this.contextMappingModel.getUserRequirements().isEmpty()) + && !modelHasSubdomainWithEntities() && this.contextMappingModel.getUserRequirements().isEmpty() + && this.contextMappingModel.getStakeholders().isEmpty()) throw new GeneratorInputException( - "Your model does not contain a) a Context Map, b) Bounded Contexts or Subdomains with domain objects (Entities, Value Objects, etc.), or c) Use Cases or User Stories. Create at least one of the mentioned model elements."); + "Your model does not contain a) a Context Map, b) Bounded Contexts or Subdomains with domain objects (Entities, Value Objects, etc.), c) Use Cases or User Stories, or d) Stakeholders or Value Registers. Create at least one of the mentioned model elements."); } private List getFlowsWithStates(BoundedContext bc) { diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java index 789474a7..99805f94 100644 --- a/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java @@ -16,8 +16,10 @@ package org.contextmapper.dsl.generator.plantuml; import java.util.List; +import java.util.stream.Collectors; import org.contextmapper.dsl.contextMappingDSL.AbstractStakeholder; +import org.contextmapper.dsl.contextMappingDSL.BoundedContext; import org.contextmapper.dsl.contextMappingDSL.Stakeholder; import org.contextmapper.dsl.contextMappingDSL.StakeholderGroup; import org.contextmapper.dsl.contextMappingDSL.Stakeholders; @@ -36,7 +38,7 @@ public class PlantUMLStakeholderMapGenerator extends AbstractPlantUMLMindMapDiag protected void printDiagramContent(final Stakeholders stakeholders) { initData(stakeholders); - sb.append(STAR).append(" ").append(stakeholders.getContexts().get(0).getName()); + sb.append(STAR).append(" ").append(getStakeholderDiagramContextName(stakeholders.getContexts())); linebreak(); printStakeholders(right); linebreak(); @@ -45,6 +47,12 @@ protected void printDiagramContent(final Stakeholders stakeholders) { printStakeholders(left); } + public String getStakeholderDiagramContextName(final List bcs) { + if (bcs != null && !bcs.isEmpty()) + return String.join(", ", bcs.stream().map(bc -> bc.getName()).collect(Collectors.toList())); + return "System of Interest"; + } + private void printStakeholders(final List stakeholders) { for (AbstractStakeholder s : stakeholders) { if (s instanceof StakeholderGroup) { From d174d9aa77176917647a7500e2b7eed79b0a0527 Mon Sep 17 00:00:00 2001 From: Stefan Kapferer Date: Fri, 9 Aug 2024 15:50:54 +0200 Subject: [PATCH 19/19] Stakeholder generator tests --- .../stakeholder-diagram-generation-test-2.cml | 44 +++++ .../stakeholder-diagram-generation-test-3.cml | 45 +++++ .../stakeholder-diagram-generation-test-4.cml | 43 +++++ ...PlantUMLStakeholderDiagramCreatorTest.java | 155 ++++++++++++++++++ 4 files changed, 287 insertions(+) create mode 100644 org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-2.cml create mode 100644 org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-3.cml create mode 100644 org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-4.cml create mode 100644 org.contextmapper.dsl.tests/src/org/contextmapper/dsl/generators/plantuml/PlantUMLStakeholderDiagramCreatorTest.java diff --git a/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-2.cml b/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-2.cml new file mode 100644 index 00000000..d14f2a18 --- /dev/null +++ b/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-2.cml @@ -0,0 +1,44 @@ +BoundedContext SameDayDelivery + +Stakeholders of SameDayDelivery { + StakeholderGroup Online_Shopping_Company { + Stakeholder Development_Team { + influence MEDIUM + interest HIGH + } + Stakeholder Product_Management { + influence HIGH + interest HIGH + } + Stakeholder Customer_Relationship_Manager { + influence HIGH + interest MEDIUM + } + } + + StakeholderGroup Product_Suppliers { + Stakeholder Managers + Stakeholder Logistics_Warehouse_Staff_of_Suppliers + Stakeholder Delivery_Staff_of_Suppliers + } + + StakeholderGroup Delivery_Partners { + Stakeholder Route_Planners + Stakeholder Drivers + } + + StakeholderGroup Competing_Companies + + StakeholderGroup Logistics_Team { + Stakeholder Logistics_Manager + Stakeholder Warehouse_Staff + } + + + Stakeholder Government + + StakeholderGroup Customers_and_Shoppers { + Stakeholder Shoppers_in_Emergency_Situations + Stakeholder Others + } +} \ No newline at end of file diff --git a/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-3.cml b/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-3.cml new file mode 100644 index 00000000..23316713 --- /dev/null +++ b/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-3.cml @@ -0,0 +1,45 @@ +BoundedContext SameDayDelivery +BoundedContext Context2 + +Stakeholders of SameDayDelivery, Context2 { + StakeholderGroup Online_Shopping_Company { + Stakeholder Development_Team { + influence MEDIUM + interest HIGH + } + Stakeholder Product_Management { + influence HIGH + interest HIGH + } + Stakeholder Customer_Relationship_Manager { + influence HIGH + interest MEDIUM + } + } + + StakeholderGroup Product_Suppliers { + Stakeholder Managers + Stakeholder Logistics_Warehouse_Staff_of_Suppliers + Stakeholder Delivery_Staff_of_Suppliers + } + + StakeholderGroup Delivery_Partners { + Stakeholder Route_Planners + Stakeholder Drivers + } + + StakeholderGroup Competing_Companies + + StakeholderGroup Logistics_Team { + Stakeholder Logistics_Manager + Stakeholder Warehouse_Staff + } + + + Stakeholder Government + + StakeholderGroup Customers_and_Shoppers { + Stakeholder Shoppers_in_Emergency_Situations + Stakeholder Others + } +} \ No newline at end of file diff --git a/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-4.cml b/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-4.cml new file mode 100644 index 00000000..742ddaa9 --- /dev/null +++ b/org.contextmapper.dsl.tests/integ-test-files/generators/plantuml/stakeholder-diagram-generation-test-4.cml @@ -0,0 +1,43 @@ + +Stakeholders { + StakeholderGroup Online_Shopping_Company { + Stakeholder Development_Team { + influence MEDIUM + interest HIGH + } + Stakeholder Product_Management { + influence HIGH + interest HIGH + } + Stakeholder Customer_Relationship_Manager { + influence HIGH + interest MEDIUM + } + } + + StakeholderGroup Product_Suppliers { + Stakeholder Managers + Stakeholder Logistics_Warehouse_Staff_of_Suppliers + Stakeholder Delivery_Staff_of_Suppliers + } + + StakeholderGroup Delivery_Partners { + Stakeholder Route_Planners + Stakeholder Drivers + } + + StakeholderGroup Competing_Companies + + StakeholderGroup Logistics_Team { + Stakeholder Logistics_Manager + Stakeholder Warehouse_Staff + } + + + Stakeholder Government + + StakeholderGroup Customers_and_Shoppers { + Stakeholder Shoppers_in_Emergency_Situations + Stakeholder Others + } +} \ No newline at end of file diff --git a/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/generators/plantuml/PlantUMLStakeholderDiagramCreatorTest.java b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/generators/plantuml/PlantUMLStakeholderDiagramCreatorTest.java new file mode 100644 index 00000000..70820546 --- /dev/null +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/generators/plantuml/PlantUMLStakeholderDiagramCreatorTest.java @@ -0,0 +1,155 @@ +/* + * Copyright 2024 The Context Mapper Project Team + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.contextmapper.dsl.generators.plantuml; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; + +import org.contextmapper.dsl.AbstractCMLInputFileTest; +import org.contextmapper.dsl.contextMappingDSL.ContextMappingModel; +import org.contextmapper.dsl.generator.plantuml.PlantUMLStakeholderMapGenerator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class PlantUMLStakeholderDiagramCreatorTest extends AbstractCMLInputFileTest { + + @BeforeEach + public void prepare() { + super.prepare(); + } + + @Test + public void canCreateStakeholderDiagramWithContext() throws IOException { + // given + ContextMappingModel model = getOriginalResourceOfTestCML("stakeholder-diagram-generation-test-2.cml").getContextMappingModel(); + + // when + String stakeholderDiagram = new PlantUMLStakeholderMapGenerator().createDiagram(model.getStakeholders().get(0)); + + // then + assertEquals("@startmindmap" + System.lineSeparator() + + System.lineSeparator() + + "* SameDayDelivery" + System.lineSeparator() + + "** Product_Suppliers" + System.lineSeparator() + + "*** Managers" + System.lineSeparator() + + "*** Logistics_Warehouse_Staff_of_Suppliers" + System.lineSeparator() + + "*** Delivery_Staff_of_Suppliers" + System.lineSeparator() + + "** Competing_Companies" + System.lineSeparator() + + "** Government" + System.lineSeparator() + + System.lineSeparator() + + "left side" + System.lineSeparator() + + "** Online_Shopping_Company" + System.lineSeparator() + + "*** Development_Team" + System.lineSeparator() + + "*** Product_Management" + System.lineSeparator() + + "*** Customer_Relationship_Manager" + System.lineSeparator() + + "** Delivery_Partners" + System.lineSeparator() + + "*** Route_Planners" + System.lineSeparator() + + "*** Drivers" + System.lineSeparator() + + "** Logistics_Team" + System.lineSeparator() + + "*** Logistics_Manager" + System.lineSeparator() + + "*** Warehouse_Staff" + System.lineSeparator() + + "** Customers_and_Shoppers" + System.lineSeparator() + + "*** Shoppers_in_Emergency_Situations" + System.lineSeparator() + + "*** Others" + System.lineSeparator() + + System.lineSeparator() + + System.lineSeparator() + + "@endmindmap" + System.lineSeparator(), stakeholderDiagram); + } + + @Test + public void canCreateStakeholderDiagramWithMultipleContext() throws IOException { + // given + ContextMappingModel model = getOriginalResourceOfTestCML("stakeholder-diagram-generation-test-3.cml").getContextMappingModel(); + + // when + String stakeholderDiagram = new PlantUMLStakeholderMapGenerator().createDiagram(model.getStakeholders().get(0)); + + // then + assertEquals("@startmindmap" + System.lineSeparator() + + System.lineSeparator() + + "* SameDayDelivery, Context2" + System.lineSeparator() + + "** Product_Suppliers" + System.lineSeparator() + + "*** Managers" + System.lineSeparator() + + "*** Logistics_Warehouse_Staff_of_Suppliers" + System.lineSeparator() + + "*** Delivery_Staff_of_Suppliers" + System.lineSeparator() + + "** Competing_Companies" + System.lineSeparator() + + "** Government" + System.lineSeparator() + + System.lineSeparator() + + "left side" + System.lineSeparator() + + "** Online_Shopping_Company" + System.lineSeparator() + + "*** Development_Team" + System.lineSeparator() + + "*** Product_Management" + System.lineSeparator() + + "*** Customer_Relationship_Manager" + System.lineSeparator() + + "** Delivery_Partners" + System.lineSeparator() + + "*** Route_Planners" + System.lineSeparator() + + "*** Drivers" + System.lineSeparator() + + "** Logistics_Team" + System.lineSeparator() + + "*** Logistics_Manager" + System.lineSeparator() + + "*** Warehouse_Staff" + System.lineSeparator() + + "** Customers_and_Shoppers" + System.lineSeparator() + + "*** Shoppers_in_Emergency_Situations" + System.lineSeparator() + + "*** Others" + System.lineSeparator() + + System.lineSeparator() + + System.lineSeparator() + + "@endmindmap" + System.lineSeparator(), stakeholderDiagram); + } + + @Test + public void canCreateStakeholderDiagramWithDefaultContext() throws IOException { + // given + ContextMappingModel model = getOriginalResourceOfTestCML("stakeholder-diagram-generation-test-4.cml").getContextMappingModel(); + + // when + String stakeholderDiagram = new PlantUMLStakeholderMapGenerator().createDiagram(model.getStakeholders().get(0)); + + // then + assertEquals("@startmindmap" + System.lineSeparator() + + System.lineSeparator() + + "* System of Interest" + System.lineSeparator() + + "** Product_Suppliers" + System.lineSeparator() + + "*** Managers" + System.lineSeparator() + + "*** Logistics_Warehouse_Staff_of_Suppliers" + System.lineSeparator() + + "*** Delivery_Staff_of_Suppliers" + System.lineSeparator() + + "** Competing_Companies" + System.lineSeparator() + + "** Government" + System.lineSeparator() + + System.lineSeparator() + + "left side" + System.lineSeparator() + + "** Online_Shopping_Company" + System.lineSeparator() + + "*** Development_Team" + System.lineSeparator() + + "*** Product_Management" + System.lineSeparator() + + "*** Customer_Relationship_Manager" + System.lineSeparator() + + "** Delivery_Partners" + System.lineSeparator() + + "*** Route_Planners" + System.lineSeparator() + + "*** Drivers" + System.lineSeparator() + + "** Logistics_Team" + System.lineSeparator() + + "*** Logistics_Manager" + System.lineSeparator() + + "*** Warehouse_Staff" + System.lineSeparator() + + "** Customers_and_Shoppers" + System.lineSeparator() + + "*** Shoppers_in_Emergency_Situations" + System.lineSeparator() + + "*** Others" + System.lineSeparator() + + System.lineSeparator() + + System.lineSeparator() + + "@endmindmap" + System.lineSeparator(), stakeholderDiagram); + } + + + @Override + protected String getTestFileDirectory() { + return "/integ-test-files/generators/plantuml/"; + } + +}