diff --git a/.github/workflows/build_master.yml b/.github/workflows/build_master.yml index 775b58b4..3f00f768 100644 --- a/.github/workflows/build_master.yml +++ b/.github/workflows/build_master.yml @@ -35,7 +35,9 @@ jobs: - name: Build with Gradle run: ./gradlew clean build - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + 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 04cb46ee..a415c54f 100644 --- a/.github/workflows/build_standard.yml +++ b/.github/workflows/build_standard.yml @@ -33,7 +33,9 @@ jobs: - name: Build with Gradle run: ./gradlew clean build - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + 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 d8279580..48efcd59 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,9 @@ jobs: - name: Build with Gradle run: ./gradlew clean build - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} build_eclipse: name: Build Eclipse Plugin 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/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/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 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" } 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..81e5f56d --- /dev/null +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/StakeholderDSLParsingTest.xtend @@ -0,0 +1,416 @@ +/* + * 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.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 + + @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 + 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); + } + + @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 new file mode 100644 index 00000000..0dee754d --- /dev/null +++ b/org.contextmapper.dsl.tests/src/org/contextmapper/dsl/ValueRegisterDSLParsingTest.xtend @@ -0,0 +1,690 @@ +/* + * 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 +import org.contextmapper.dsl.contextMappingDSL.CoreValue + +@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 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 + 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 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 + 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); + } + + @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.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.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/"; + } + +} diff --git a/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext b/org.contextmapper.dsl/src/org/contextmapper/dsl/ContextMappingDSL.xtext index c1354245..cebd031b 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)* ) ; @@ -308,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)*)? & @@ -320,9 +321,8 @@ UseCase: ; UserStory: - 'UserStory' name=ID ('split by' splittingStory=[UserStory])? - (OPEN - (('As a' | 'As an') role=STRING (features+=Feature)+ 'so that' benefit=STRING)? + 'UserStory' name=ID ('split by' splittingStory=[UserStory])? (OPEN + (('As a' | 'As an') role=STRING (features+=Feature)+ 'so that' benefit=STRING (valuation=StoryValuation)?)? CLOSE)? ; @@ -338,16 +338,21 @@ 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' ; 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) | @@ -356,6 +361,128 @@ SculptorModule : CLOSE)? ; + +Stakeholders: + {Stakeholders} 'Stakeholders' ('of' (contexts+=[BoundedContext]) (',' contexts+=[BoundedContext])*)? (OPEN + ( + (stakeholders += AbstractStakeholder)* + ) + CLOSE)? +; + +AbstractStakeholder: + StakeholderGroup | Stakeholder +; + +StakeholderGroup: + 'StakeholderGroup' name=ID (OPEN + ( + (stakeholders += Stakeholder)* + ) + CLOSE)? +; + +Stakeholder: + 'Stakeholder' name=ID (OPEN + ( + ('influence' ('=')? influence=INFLUENCE)? & + ('interest' ('=')? interest=INTEREST)? & + ('description' ('=')? description=STRING)? + ) + CLOSE)? +; + +ValueRegister: + 'ValueRegister' name=ID ('for' context=[BoundedContext])? (OPEN + ( + (valueClusters += ValueCluster)* & + (values += Value)* & + (valueEpics += ValueEpic)* & + (valueNarratives += ValueNarrative)* & + (valueWeightings += ValueWeigthing)* + ) + CLOSE)? +; + +ValueCluster: + 'ValueCluster' name=ID (OPEN + ( + (('core' ('=')? coreValue7000 = CoreValue) | ('core' ('=')? coreValue = STRING)) & + ('demonstrator' ('=')? demonstrators += STRING)* & + ('relatedValue' ('=')? relatedValues += STRING)* & + ('opposingValue' ('=')? opposingValues += STRING)* & + (values += Value)* & + (elicitations += ValueElicitation)* + ) + CLOSE)? +; + +Value: + 'Value' name=ID (OPEN + ( + (coreValue ?= 'isCore')? & + ('demonstrator' ('=')? demonstrators += STRING)* & + ('relatedValue' ('=')? relatedValues += STRING)* & + ('opposingValue' ('=')? opposingValues += STRING)* & + (elicitations += ValueElicitation)* + ) + CLOSE)? +; + +// Q: table B.1 abbilden? if, how? + +ValueElicitation: + ('Stakeholder'|'Stakeholders') stakeholder=[AbstractStakeholder] (OPEN + ( + ('priority' ('=')? priority = PRIORITY)? & + ('impact' ('=')? impact = IMPACT)? & + ('consequences' (consequences += Consequence)+)? + ) + CLOSE)? +; + + +ValueEpic: + 'ValueEpic' name=ID (OPEN + ( + 'As a' stakeholder=[AbstractStakeholder] 'I value' value=STRING 'as demonstrated in' + (('realization of' realizedValues+=STRING)+ & + ('reduction of' reducedValues+=STRING)+) + ) + CLOSE)? +; + +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) +; + +ValueWeigthing: + 'ValueWeigthing' name=ID (OPEN + ( + 'In the context of the SOI,' + '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 + ) + CLOSE) +; + +Consequence: + (type='good'|type='bad'|type='neutral') consequence=STRING action=Action? +; + +Action: + 'action' action=STRING type=('ACT'|'MONITOR'|STRING) +; + + enum UpstreamRole: PUBLISHED_LANGUAGE = 'PL' | OPEN_HOST_SERVICE = 'OHS' ; @@ -404,6 +531,26 @@ enum Evolution : UNDEFINED | GENESIS | CUSTOM_BUILT | PRODUCT | COMMODITY ; +enum INFLUENCE : + HIGH | MEDIUM | LOW +; + +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 d25fe678..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. @@ -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; @@ -31,6 +32,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; @@ -56,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)); + } - // generate class and state diagrams for Bounded Contexts + 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)); + }); + } + + private void generateClassAndStateDiagramsForBoundedContexts(ContextMappingModel model, IFileSystemAccess2 fsa, + String fileName) { for (BoundedContext boundedContext : model.getBoundedContexts()) { // class diagram for complete BC @@ -97,37 +143,21 @@ protected void generateFromContextMappingModel(ContextMappingModel model, IFileS + PLANT_UML_FILE_EXT, new PlantUMLStateDiagramCreator4Flow().createDiagram(flow)); } } + } - // 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/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..99805f94 --- /dev/null +++ b/org.contextmapper.dsl/src/org/contextmapper/dsl/generator/plantuml/PlantUMLStakeholderMapGenerator.java @@ -0,0 +1,92 @@ +/* + * 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 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; + +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 Stakeholders stakeholders) { + initData(stakeholders); + + sb.append(STAR).append(" ").append(getStakeholderDiagramContextName(stakeholders.getContexts())); + linebreak(); + printStakeholders(right); + linebreak(); + sb.append("left side"); + linebreak(); + 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) { + 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 Stakeholders stakeholders) { + left.clear(); + right.clear(); + + boolean addLeft = true; + + for (AbstractStakeholder s : stakeholders.getStakeholders()) { + if (addLeft) + left.add(s); + else + right.add(s); + + addLeft = !addLeft; + } + } + +}