Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make PcmUmlClassTests View-Based #274

Merged
merged 13 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Require-Bundle: org.eclipse.uml2.uml;visibility:=reexport,
org.palladiosimulator.pcm;visibility:=reexport,
edu.kit.ipd.sdq.activextendannotations,
edu.kit.ipd.sdq.commons.util.emf,
edu.kit.ipd.sdq.commons.util.java,
tools.vitruv.framework.applications,
tools.vitruv.dsls.reactions.runtime,
tools.vitruv.applications.util.temporary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,46 @@ import org.palladiosimulator.pcm.system.System
import org.palladiosimulator.pcm.core.entity.Entity
import tools.vitruv.applications.util.temporary.other.CorrespondenceRetriever

import static extension edu.kit.ipd.sdq.commons.util.java.lang.IterableUtil.claimOne

@Utility
class PcmUmlClassHelper {

def static Iterable<PrimitiveType> mapPrimitiveTypes(PrimitiveDataType pcmPredefinedPrimitiveType,
def static PrimitiveType mapPcmToUmlPrimitiveType(PrimitiveDataType pcmPredefinedPrimitiveType,
Iterable<PrimitiveType> umlPredefinedPrimitiveTypes) {
// Prefer UML Types over JAVA Types
return switch (pcmPredefinedPrimitiveType.type) {
case PrimitiveTypeEnum.BOOL: umlPredefinedPrimitiveTypes.filter[it.name.toLowerCase == "bool" || it.name.toLowerCase == "boolean"]
case PrimitiveTypeEnum.BYTE: umlPredefinedPrimitiveTypes.filter[it.name.toLowerCase == "byte"]
case PrimitiveTypeEnum.CHAR: umlPredefinedPrimitiveTypes.filter[it.name.toLowerCase == "char"]
case PrimitiveTypeEnum.INT: umlPredefinedPrimitiveTypes.filter[it.name.toLowerCase == "int" || it.name.toLowerCase == "integer"]
case PrimitiveTypeEnum.DOUBLE: umlPredefinedPrimitiveTypes.filter[it.name.toLowerCase == "double" || it.name.toLowerCase == "real"]
case PrimitiveTypeEnum.STRING: umlPredefinedPrimitiveTypes.filter[it.name.toLowerCase == "string"]
case PrimitiveTypeEnum.BOOL: umlPredefinedPrimitiveTypes.filter[it.name == "Boolean"].claimOne
case PrimitiveTypeEnum.INT: umlPredefinedPrimitiveTypes.filter[it.name == "Integer"].claimOne
case PrimitiveTypeEnum.DOUBLE: umlPredefinedPrimitiveTypes.filter[it.name == "Real"].claimOne
case PrimitiveTypeEnum.STRING: umlPredefinedPrimitiveTypes.filter[it.name == "String"].claimOne
case PrimitiveTypeEnum.BYTE: umlPredefinedPrimitiveTypes.filter[it.name == "byte"].claimOne
case PrimitiveTypeEnum.CHAR: umlPredefinedPrimitiveTypes.filter[it.name == "char"].claimOne
case PrimitiveTypeEnum.LONG: umlPredefinedPrimitiveTypes.filter[it.name == "Real"].claimOne
default: null
// uml::UnlimitedNatural are not mapped and the user is notified if one of these types is set
// uml::UnlimitedNatural are not mapped and the user is notified if one of these types is set
}
}


def static PrimitiveDataType mapUmlToPcmPrimitiveType(PrimitiveType umlPrimitiveDataType, Iterable<PrimitiveDataType> pcmPrimitiveDataTypes) {
return switch (umlPrimitiveDataType.name.toLowerCase) {
case "bool",
case "boolean": pcmPrimitiveDataTypes.filter[it.type == PrimitiveTypeEnum.BOOL].head
case "short",
case "integer",
case "int": pcmPrimitiveDataTypes.filter[it.type == PrimitiveTypeEnum.INT].head
case "string": pcmPrimitiveDataTypes.filter[it.type == PrimitiveTypeEnum.STRING].head
case "real",
case "float",
case "double": pcmPrimitiveDataTypes.filter[it.type == PrimitiveTypeEnum.DOUBLE].head
case "char": pcmPrimitiveDataTypes.filter[it.type == PrimitiveTypeEnum.CHAR].head
case "byte": pcmPrimitiveDataTypes.filter[it.type == PrimitiveTypeEnum.BYTE].head
case "long": pcmPrimitiveDataTypes.filter[it.type == PrimitiveTypeEnum.LONG].head
default: null
// uml::UnlimitedNatural are not mapped and the user is notified if one of these types is set
}
}

def static getMatchingParameterDirection(ParameterModifier pcmModifier) {
return switch (pcmModifier) {
case IN: ParameterDirectionKind.IN_LITERAL
Expand Down Expand Up @@ -76,8 +99,12 @@ class PcmUmlClassHelper {
Repository pcmRepository, UserInteractor userInteractor, CorrespondenceRetriever correspondenceRetriever) {
if(umlType === null) return null

val pcmPrimitiveType = correspondenceRetriever.retrieveCorrespondingElement(umlType,
PrimitiveDataType, TagLiterals.DATATYPE__TYPE) as PrimitiveDataType
var pcmPrimitiveType = correspondenceRetriever.retrieveCorrespondingElement(umlType,
PrimitiveDataType, TagLiterals.DATATYPE__TYPE) as PrimitiveDataType
if(pcmPrimitiveType === null) {
pcmPrimitiveType = correspondenceRetriever.retrieveCorrespondingElement(umlType,
PrimitiveDataType, TagLiterals.DATATYPE__TYPE__ALTERNATIVE) as PrimitiveDataType
}
val pcmCompositeType = correspondenceRetriever.retrieveCorrespondingElement(umlType,
CompositeDataType, TagLiterals.COMPOSITE_DATATYPE__CLASS) as CompositeDataType
val pcmSimpleType = #[pcmPrimitiveType, pcmCompositeType].findFirst[it !== null]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ private TagLiterals() {
* correspondences
*/
public static final String DATATYPE__TYPE = "datatype";
/**
* There is a 1:n relation between PCM and UML PrimitiveDataTypes.
* The correspondences of the prefered mapping from PCM to UML is stored with tag DATATYPE__TYPE.
* In case a not prefered UML Datatype is used anyway in the UML model, the tag DATATYPE__TYPE__ALTERNATIVE
* stores also correspondences between not prefered UML datatypes and corresponding PCM datatypes.
*/
public static final String DATATYPE__TYPE__ALTERNATIVE = "datatype-alternative";

public static final String INNER_DECLARATION__PROPERTY = "composite-inner-property";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,24 +175,33 @@ routine bootstrapPrimitiveDatatypes(pcm::Repository pcmRepo) {
update {
val pcmPrimitiveTypes = PcmDataTypeUtil.getPcmPrimitiveTypes(pcmRepo)
val umlPrimitiveTypes = UmlTypeUtil.getUmlPrimitiveTypes(pcmRepo.eResource.resourceSet)

// store primary correspondces for prefered mapping between PCM and UML PrimitiveDatatypes
for (pcmType : pcmPrimitiveTypes) {
val umlTypes = PcmUmlClassHelper.mapPrimitiveTypes(pcmType, umlPrimitiveTypes)
for (umlType : umlTypes) {
addPrimitiveDatatypeCorrespondence(pcmType, umlType)
val umlType = PcmUmlClassHelper.mapPcmToUmlPrimitiveType(pcmType, umlPrimitiveTypes)
if (umlType !== null) {
addPrimitiveDatatypeCorrespondence(pcmType, umlType, TagLiterals.DATATYPE__TYPE)
}
}

// store alternative correspondces for mapping between PCM and UML PrimitiveDatatypes in case non prefered UML datatypes are used
for (umlType : umlPrimitiveTypes) {
val pcmType = PcmUmlClassHelper.mapUmlToPcmPrimitiveType(umlType, pcmPrimitiveTypes)
if (pcmType !== null) {
addPrimitiveDatatypeCorrespondence(pcmType, umlType, TagLiterals.DATATYPE__TYPE__ALTERNATIVE)
}
}
}
}

routine addPrimitiveDatatypeCorrespondence(pcm::PrimitiveDataType pcmPrimitiveType, uml::PrimitiveType umlPrimitiveType) {
routine addPrimitiveDatatypeCorrespondence(pcm::PrimitiveDataType pcmPrimitiveType, uml::PrimitiveType umlPrimitiveType, String tag) {
match {
require absence of uml::PrimitiveType corresponding to pcmPrimitiveType tagged TagLiterals.
DATATYPE__TYPE with it == umlPrimitiveType
require absence of pcm::PrimitiveDataType corresponding to umlPrimitiveType tagged TagLiterals.
DATATYPE__TYPE with it == pcmPrimitiveType
require absence of uml::PrimitiveType corresponding to pcmPrimitiveType tagged tag with it == umlPrimitiveType
require absence of pcm::PrimitiveDataType corresponding to umlPrimitiveType tagged tag with it ==
pcmPrimitiveType
}
update {
addCorrespondenceBetween(pcmPrimitiveType, umlPrimitiveType, TagLiterals.DATATYPE__TYPE)
addCorrespondenceBetween(pcmPrimitiveType, umlPrimitiveType, tag)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Require-Bundle: tools.vitruv.testutils.vsum,
edu.kit.ipd.sdq.commons.util.java,
org.palladiosimulator.pcm.resources,
edu.kit.ipd.sdq.activextendannotations,
tools.vitruv.applications.testutility
tools.vitruv.applications.testutility,
org.palladiosimulator.pcm,
edu.kit.ipd.sdq.commons.util.emf
Export-Package: tools.vitruv.applications.pcmumlclass.tests
Bundle-Vendor: vitruv.tools
Original file line number Diff line number Diff line change
@@ -1,111 +1,81 @@
package tools.vitruv.applications.pcmumlclass.tests

import org.eclipse.uml2.uml.Property
import org.palladiosimulator.pcm.core.composition.AssemblyContext
import org.palladiosimulator.pcm.core.composition.CompositionFactory
import org.palladiosimulator.pcm.repository.Repository
import tools.vitruv.applications.pcmumlclass.TagLiterals
import org.junit.jupiter.api.Test
import static org.junit.jupiter.api.Assertions.assertNotNull
import static org.junit.jupiter.api.Assertions.assertTrue
import java.nio.file.Path
import org.palladiosimulator.pcm.core.composition.CompositionFactory
import tools.vitruv.applications.pcmumlclass.tests.helper.FluentPCMCompositeComponentBuilder
import tools.vitruv.applications.pcmumlclass.tests.helper.FluentPCMRepositoryBuilder
import tools.vitruv.applications.pcmumlclass.tests.helper.FluentUMLClassBuilder
import tools.vitruv.applications.pcmumlclass.tests.helper.FluentUMLPackageBuilder

/**
* This test class tests the reactions and routines that are supposed to synchronize a pcm::AssemblyContext
* in a pcm::ComposedProvidingRequiringEntity (CPRE) with a uml::Property in an uml::Class (the implementation class to the CPRE).
* <br><br>
* Related files: PcmAssemblyContext.reactions, UmlAssemblyContextProperty.reactions
*/
class AssemblyContextConceptTest extends LegacyPcmUmlClassApplicationTest {

class AssemblyContextConceptTest extends PcmUmlClassApplicationTest {
static val PROPERTY_NAME = "testAssemblyContextField"

def void checkAssemblyContextConcept(
AssemblyContext pcmAssemblyContext,
Property umlAssemblyContextProperty
) {
assertNotNull(pcmAssemblyContext)
assertNotNull(umlAssemblyContextProperty)
assertTrue(
corresponds(pcmAssemblyContext, umlAssemblyContextProperty, TagLiterals.ASSEMBLY_CONTEXT__PROPERTY))
assertTrue(
corresponds(pcmAssemblyContext.parentStructure__AssemblyContext, umlAssemblyContextProperty.owner,
TagLiterals.IPRE__IMPLEMENTATION))
assertTrue(
corresponds( pcmAssemblyContext.encapsulatedComponent__AssemblyContext, umlAssemblyContextProperty.type,
TagLiterals.IPRE__IMPLEMENTATION))
assertTrue(pcmAssemblyContext.entityName == umlAssemblyContextProperty.name)
}

def protected checkAssemblyContextConcept(AssemblyContext pcmAssemblyContext) {
val umlAssemblyContextProperty = helper.getModifiableCorr(pcmAssemblyContext, Property,
TagLiterals.ASSEMBLY_CONTEXT__PROPERTY)
checkAssemblyContextConcept(pcmAssemblyContext, umlAssemblyContextProperty)
}

def protected checkAssemblyContextConcept(Property umlAssemblyContextProperty) {
val pcmAssemblyContext = helper.getModifiableCorr(umlAssemblyContextProperty, AssemblyContext,
TagLiterals.ASSEMBLY_CONTEXT__PROPERTY)
checkAssemblyContextConcept(pcmAssemblyContext, umlAssemblyContextProperty)
}

/**
* Initialize a pcm::Repository with two CompositeComponents and synchronize them with their uml-counterparts.
*/
def private Repository createRepository_2Components() {

val pcmRepository = helper.createRepository
helper.createComponent(pcmRepository)
helper.createComponent_2(pcmRepository)
private def void createRepositoryWithTwoComponents() {
initPCMRepository()

userInteraction.addNextTextInput(LegacyPcmUmlClassApplicationTestHelper.UML_MODEL_FILE)
resourceAt(Path.of(LegacyPcmUmlClassApplicationTestHelper.PCM_MODEL_FILE)).startRecordingChanges => [
contents += pcmRepository
changePcmView[
PcmUmlClassApplicationTestHelper.createComponent(defaultPcmRepository)
PcmUmlClassApplicationTestHelper.createComponent_2(defaultPcmRepository)
]
propagate
assertModelExists(LegacyPcmUmlClassApplicationTestHelper.PCM_MODEL_FILE)
assertModelExists(LegacyPcmUmlClassApplicationTestHelper.UML_MODEL_FILE)

return pcmRepository.clearResourcesAndReloadRoot
}

@Test
def void testCreateAssemblyContextConcept_PCM() {
var pcmRepository = createRepository_2Components()
var pcmComponent = helper.getPcmComponent(pcmRepository)
createRepositoryWithTwoComponents()

var pcmAssemblyContext = CompositionFactory.eINSTANCE.createAssemblyContext
pcmAssemblyContext.entityName = PROPERTY_NAME
// TODO setting the same component as container and encapsulated doesn't seem to trigger change event
pcmAssemblyContext.encapsulatedComponent__AssemblyContext = helper.getPcmComponent_2(pcmRepository)
pcmComponent.assemblyContexts__ComposedStructure += pcmAssemblyContext
changePcmView[
val pcmComponent1 = PcmUmlClassApplicationTestHelper.getPcmComponent(defaultPcmRepository)
val pcmComponent2 = PcmUmlClassApplicationTestHelper.getPcmComponent_2(defaultPcmRepository)

propagate
pcmRepository = pcmRepository.clearResourcesAndReloadRoot
var pcmAssemblyContext = CompositionFactory.eINSTANCE.createAssemblyContext
pcmAssemblyContext.entityName = PROPERTY_NAME
// TODO setting the same component as container and encapsulated doesn't seem to trigger change event
pcmAssemblyContext.encapsulatedComponent__AssemblyContext = pcmComponent2
pcmComponent1.assemblyContexts__ComposedStructure += pcmAssemblyContext
]

pcmAssemblyContext = helper.getPcmComponent(pcmRepository).assemblyContexts__ComposedStructure.head
assertNotNull(pcmAssemblyContext)
checkAssemblyContextConcept(pcmAssemblyContext)
validateUmlView[
val component2Class = new FluentUMLClassBuilder(PcmUmlClassApplicationTestHelper.COMPONENT_NAME_2_USC +
PcmUmlClassApplicationTestHelper.IMPL_SUFFIX, true).addDefaultConstructor.build
val component1Class = new FluentUMLClassBuilder(PcmUmlClassApplicationTestHelper.COMPONENT_NAME_USC +
PcmUmlClassApplicationTestHelper.IMPL_SUFFIX, true).addDefaultConstructor.addAttribute(PROPERTY_NAME,
component2Class).build
val component1Package = new FluentUMLPackageBuilder(PcmUmlClassApplicationTestHelper.COMPONENT_NAME_LSC).
addPackagedElement(component1Class).build
assertEqualityAndContainmentOfUmlPackage(defaultUmlModel,
String.join(".", PACKAGE_NAME, PcmUmlClassApplicationTestHelper.COMPONENT_NAME_LSC), component1Package)
]
}

@Test
def void testCreateAssemblyContextConcept_UML() {
var pcmRepository = createRepository_2Components()
var umlComponent = helper.getUmlComponentImpl(pcmRepository)
startRecordingChanges(umlComponent)
createRepositoryWithTwoComponents()

changeUmlView[
val umlComponent1Class = PcmUmlClassApplicationTestHelper.claimClass(defaultUmlModel,
PcmUmlClassApplicationTestHelper.COMPONENT_NAME_USC + PcmUmlClassApplicationTestHelper.IMPL_SUFFIX)
val umlComponent2Class = PcmUmlClassApplicationTestHelper.claimClass(defaultUmlModel,
PcmUmlClassApplicationTestHelper.COMPONENT_NAME_2_USC + PcmUmlClassApplicationTestHelper.IMPL_SUFFIX)

var umlAssemblyContextProperty = umlComponent.createOwnedAttribute(PROPERTY_NAME,
helper.getUmlComponentImpl_2(pcmRepository))
umlComponent1Class.createOwnedAttribute(PROPERTY_NAME, umlComponent2Class)
]

propagate
umlAssemblyContextProperty.clearResourcesAndReloadRoot
pcmRepository = pcmRepository.clearResourcesAndReloadRoot
validatePcmView[
val pcmComponent2 = new FluentPCMCompositeComponentBuilder(
PcmUmlClassApplicationTestHelper.COMPONENT_NAME_2_USC).build
val pcmComponent1 = new FluentPCMCompositeComponentBuilder(
PcmUmlClassApplicationTestHelper.COMPONENT_NAME_USC).addAssemblyContext(PROPERTY_NAME, pcmComponent2).
build
val expectedRepository = new FluentPCMRepositoryBuilder(PACKAGE_NAME_FIRST_UPPER).addComponent(
pcmComponent1).addComponent(pcmComponent2).build

umlAssemblyContextProperty = helper.getUmlComponentImpl(pcmRepository).ownedAttributes.findFirst [
it.name == PROPERTY_NAME
assertEqualityOfPcmRepository(defaultPcmRepository, expectedRepository)
]
assertNotNull(umlAssemblyContextProperty)
checkAssemblyContextConcept(umlAssemblyContextProperty)
}

}
Loading