diff --git a/plugins/org.etsi.mts.tdl.model/model/tdl-constraints.ocl b/plugins/org.etsi.mts.tdl.model/model/tdl-constraints.ocl index ca4b024c3a8527ee7fa14cb035dc92b0e150c9ed..5e7ac326cc698212e151994d4b05e37352a3a1f2 100644 --- a/plugins/org.etsi.mts.tdl.model/model/tdl-constraints.ocl +++ b/plugins/org.etsi.mts.tdl.model/model/tdl-constraints.ocl @@ -10,9 +10,6 @@ context NamedElement -- Distinguishable qualified names inv DistinquishableName ('All qualified names of instances of \'NamedElement\'s shall be distinguishable within a TDL model.' + self.toString()): --- TODO: Weird workaround, not sure why it is needed - self.oclIsTypeOf(EnumDataType) - or NamedElement.allInstances()->one(e | e.qualifiedName = self.qualifiedName) @@ -266,33 +263,57 @@ context EnumDataType context DataUse -- Occurrence of 'argument' and 'reduction' - inv ArgumentReductionLists ('Only in case of a \'FunctionCall\' both the \'argument\' list and the \'reduction\' list may be provided, otherwise either the \'argument\' list, the \'reduction\' list, or none of them shall be provided.' + self.toString()): + inv ArgumentReductionLists ('Only in case of a \'FunctionCall\', or a \'DataElementUse\' which refers to a \'Function\', both the \'argument\' list and the \'reduction\' list may be provided, otherwise either the \'argument\' list, the \'reduction\' list, or none of them shall be provided.' + self.toString()): self.argument->isEmpty() or self.reduction->isEmpty() or self.oclIsTypeOf(FunctionCall) + or (self.oclIsTypeOf(DataElementUse) + and self.oclAsType(DataElementUse).dataElement.oclIsTypeOf(Function)) - -- Structured data types in 'reduction' set - inv ReductionMembers ('The \'Member\' referenced by the \'MemberReference\' at index i of a \'reduction\' shall be contained in or inherited by the \'StructuredDataType\' of the \'Member\' referenced by the \'MemberReference\' at index (i - 1) of that \'reduction\'.' + self.toString()): - not self.resolveDataType().oclIsKindOf(StructuredDataType) - or self.reduction->isEmpty() - or self.resolveDataType().oclAsType(StructuredDataType).allMembers()->includes(self.reduction->first().member) - and self.reduction->select(m | self.reduction->indexOf(m) > 1)->forAll(m | - self.reduction->at(self.reduction->indexOf(m)-1).member.dataType.oclIsKindOf(StructuredDataType) - and self.reduction->at(self.reduction->indexOf(m)-1).member.dataType.oclAsType(StructuredDataType).allMembers() - ->includes(m.member)) + -- Members in 'reduction' list + inv ReductionMembers ('The \'Member\' referenced by the \'MemberReference\' at index i of a \'reduction\' shall be contained in or inherited by the \'StructuredDataType\' of the \'Member\' referenced by the \'MemberReference\' at index (i - 1) of that \'reduction\' or the \'StructuredDataType\' of this \'DataUse\' if the \'MemberReference\' is the first element of the \'reduction\'.' + self.toString()): + self.reduction->isEmpty() + or self.reduction->reject(r | self.reduction->indexOf(r) = 1) + ->iterate(r; acc = Sequence{Sequence{self.resolveBaseDataType(), self.reduction->at(1)}} + | acc->including(Sequence{self.reduction->at(self.reduction->indexOf(r) - 1)->asSequence() + ->reject(r|r.member.oclIsUndefined()).member.dataType->including(self.resolveBaseDataType())->at(1), r + })) + ->reject(tr | tr->at(1).oclIsUndefined() or tr->at(2).oclAsType(MemberReference).member.oclIsUndefined()) + ->iterate(tr; acc = Sequence{} | acc->including(Sequence{tr->at(1)->asSequence() + ->select(t|t.oclIsKindOf(CollectionDataType)).oclAsType(CollectionDataType).itemType->including(tr->at(1))->at(1), tr->at(2) + })) + ->forAll(tr | tr->at(1).oclAsType(StructuredDataType).allMembers()->includes(tr->at(2).oclAsType(MemberReference).member)) - -- No member with collection index in the first element in reduction - inv FirstReduction ('The first \'MemberReference\' in reduction shall not specify both member and collectionIndex. ' + self.toString()): - self.reduction->first().member.oclIsUndefined() or self.reduction->first().collectionIndex.oclIsUndefined() + -- Collection index of first 'reduction' + inv ReductionMembers ('If the \'member\' is not specified for the first element of the \'reduction\' then the type of this \'DataUse\' shall be \'CollectionDataType\'.' + self.toString()): + self.reduction->isEmpty() + or not self.reduction->at(1).member.oclIsUndefined() + or self. resolveBaseDataType().oclIsKindOf(CollectionDataType) context ParameterBinding - -- Matching data type - inv ParameterBindingTypes ('The provided \'DataUse\' shall conform to the \'DataType\' of the referenced \'Parameter\'.' + self.toString()): - self.dataUse.resolveDataType().conformsTo(self.resolveParameterType()) - or self.dataUse.oclIsKindOf(SpecialValueUse) + -- Members in 'reduction' list of parameter + inv ReductionMembers ('The \'Member\' referenced by the \'MemberReference\' at index i of a \'reduction\' shall be contained in or inherited by the \'StructuredDataType\' of the \'Member\' referenced by the \'MemberReference\' at index (i - 1) of that \'reduction\' or the \'StructuredDataType\' of the \'parameter\' if the \'MemberReference\' is the first element of the \'reduction\'.' + self.toString()): + self.reduction->isEmpty() + or self.reduction->reject(r | self.reduction->indexOf(r) = 1) + ->iterate(r; acc = Sequence{Sequence{self.parameter.dataType, self.reduction->at(1)}} + | acc->including(Sequence{self.reduction->at(self.reduction->indexOf(r) - 1)->asSequence() + ->reject(r|r.member.oclIsUndefined()).member.dataType->including(self.parameter.dataType)->at(1), r + })) + ->reject(tr | tr->at(1).oclIsUndefined() or tr->at(2).oclAsType(MemberReference).member.oclIsUndefined()) + ->iterate(tr; acc = Sequence{} | acc->including(Sequence{tr->at(1)->asSequence() + ->select(t|t.oclIsKindOf(CollectionDataType)).oclAsType(CollectionDataType).itemType->including(tr->at(1))->at(1), tr->at(2) + })) + ->forAll(tr | tr->at(1).oclAsType(StructuredDataType).allMembers()->includes(tr->at(2).oclAsType(MemberReference).member)) + + + -- Collection index of first 'reduction' of parameter + inv ReductionMembers ('If the \'member\' is not specified for the first element of the \'reduction\' then the type of the \'parameter\' shall be \'CollectionDataType\'.' + self.toString()): + self.reduction->isEmpty() + or not self.reduction->at(1).member.oclIsUndefined() + or self.parameter.dataType.oclIsKindOf(CollectionDataType) -- Use of a 'StructuredDataInstance' with non-optional 'Member's @@ -305,10 +326,10 @@ context ParameterBinding context MemberReference -- Collection index expressions for collections only - inv CollectionIndex ('If the type of the related \'DataUse\' is not \'CollectionDataType\' then the collectionIndex shall be undefined. ' + self.toString()): + inv CollectionIndex ('If the \'member\' is specified and the type of the \'member\' is not \'CollectionDataType\' then the collectionIndex shall be undefined. ' + self.toString()): self.collectionIndex.oclIsUndefined() - or self.container().oclIsTypeOf(ParameterBinding) --and self.container().oclAsType(ParameterBinding).resolveDataType().oclIsKindOf(CollectionDataType) - or self.container().oclAsType(DataUse).resolveDataType().oclIsKindOf(CollectionDataType) + or self.member.oclIsUndefined() + or self.member.dataType.oclIsKindOf(CollectionDataType) -- Either member or collection index is required @@ -376,7 +397,7 @@ context PredefinedFunctionCall context LiteralValueUse -- Exactly one value specification - inv SpecifiedLiteralValue ('There shall be exactly one value specification, where either the \'value\', or the \'intValue\', or the \'boolValue\' property is be specified, but not more than one of them.' + self.toString()): + inv SpecifiedLiteralValue ('There shall be exactly one value specification, where either the \'value\', or the \'intValue\', or the \'boolValue\' property is specified, but not more than one of them.' + self.toString()): not self.value.oclIsUndefined() xor not self.intValue.oclIsUndefined() xor not self.boolValue.oclIsUndefined() @@ -406,8 +427,12 @@ context DataElementUse -- 'DataElement' reference or non-empty 'argument' or non-empty 'item' inv DataInstanceOrArgumentsOrItemsInDataElementUse ('If a \'dataElement\' is not specified, or if the \'dataElement\' is resolved to a \'StructuredDataType\' or a \'CollectionDataType\', either a non-empty \'argument\' set or a non-empty \'item\' set shall be specified.' + self.toString()): not (self.dataElement.oclIsUndefined() and self.argument->isEmpty() and self.item->isEmpty()) - and (self.dataElement.oclIsKindOf(StructuredDataInstance) or not (self.resolveDataType().oclIsKindOf(StructuredDataType) and self.argument->isEmpty())) - and (self.dataElement.oclIsKindOf(CollectionDataInstance) or not (self.resolveDataType().oclIsKindOf(CollectionDataType) and self.item->isEmpty())) + and (self.dataElement.oclIsKindOf(StructuredDataInstance) + or not (self.resolveDataType().oclIsKindOf(StructuredDataType) + and self.argument->isEmpty())) + and (self.dataElement.oclIsKindOf(CollectionDataInstance) + or not (self.resolveDataType().oclIsKindOf(CollectionDataType) + and self.item->isEmpty())) -- Valid 'DataType' for items @@ -425,14 +450,20 @@ context DataElementUse -- Matching parameters for 'Function's inv FunctionCallParameters ('All \'FormalParameter\'s shall be bound if the \'dataElement\' refers to a \'Function\'.' + self.toString()): - self.dataElement.oclIsUndefined() - or - not self.dataElement.oclIsKindOf(Function) + not self.dataElement.oclIsTypeOf(Function) or self.dataElement.oclAsType(Function).formalParameter->forAll(p | self.argument->exists(a | a.parameter = p)) +context CastDataUse + -- Compatible 'DataType's + inv CompatibleDataTypesInCastDataUse ('The specified \'dataType\' shall directly or indirectly extend the resolved \'DataType\' of the specified \'dataUse\'.' + self.toString()): + self.dataType.conformsTo(self.dataUse.resolveDataType()) + + + + context TimeLabelUse -- Empty 'argument' and 'reduction' sets inv TimeLabelArgumentReduction ('The \'argument\' and \'reduction\' sets shall be empty.' + self.toString()): @@ -700,54 +731,49 @@ context AlternativeBehaviour -- First behaviour of 'Block's inv FirstBlockBehaviour ('Each block of an \'AlternativeBehaviour\' shall start with a tester-input event. ' + self.toString()): - self.block->forAll(b | b.behaviour->isEmpty() or b.behaviour->first().isTesterInputEvent()) + self.block->forAll(b | b.behaviour->first().isTesterInputEvent()) -- Same component if locally ordered inv AlternativeBlocksComponent ('If the containing \'TestDescription\' is locally ordered then all \'Block\'s shall start with a tester-input event of the same \'ComponentInstance\'. ' + self.toString()): - let initials = self.block->reject(b | b.behaviour->first()->isEmpty() or b.behaviour->first().oclIsKindOf(OptionalBehaviour)).behaviour->first() - in + let initial = self.block.behaviour->first() in Set{} - ->union(initials->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component) - ->union(initials->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance) - ->union(initials->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance) + ->including(initial->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component) + ->including(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance) + -> including(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance) ->size() = 1 or not self.getParentTestDescription().isLocallyOrdered -- Tester participating in locally ordered case inv AlternativeBehaviourParticipation ('If the \'AlternativeBehaviour\' is contained in a locally ordered \'TestDescription\' then no other tester \'ComponentInstance\' shall participate in any block than the target of the first tester-input event and \'ComponentInstance\'s participating in blocks of contained \'OptionalBehaviour\'s. ' + self.toString()): - let initials = self.block->reject(b | b.behaviour->first()->isEmpty() or b.behaviour->first().oclIsKindOf(OptionalBehaviour)).behaviour->first(), + let initial = self.block.behaviour->first(), targetComponent = Set{} - ->union(initials->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component) - ->union(initials->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance) - -> union(initials->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance), + ->including(initial->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component) + ->including(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance) + -> including(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance), nonOptionalBlocks = self.block->closure( b | b.behaviour->reject(oclIsKindOf(OptionalBehaviour)) ->select(oclIsKindOf(SingleCombinedBehaviour)).oclAsType(SingleCombinedBehaviour).block - ->union(b.behaviour + ->union(b.behaviour->reject(oclIsKindOf(OptionalBehaviour)) ->select(oclIsKindOf(MultipleCombinedBehaviour)).oclAsType(MultipleCombinedBehaviour).block) ) in - targetComponent->includesAll( + targetComponent->includesAll( nonOptionalBlocks.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole::SUT)) - or not self.getParentTestDescription().isLocallyOrdered + or not self.getParentTestDescription().isLocallyOrdered -- OptionalBehaviour in locally ordered case inv OptionalAlternativeBehaviour ('A block of an \'AlternativeBehaviour\' if the containing \'TestDescription\' is locally ordered, shall only contain \'OptionalBehaviour\'(s) whose source \'ComponentInstance\' is the same as the target of the first tester-input event of that \'Block\'. ' + self.toString()): - let initials = self.block->reject(b | b.behaviour->first()->isEmpty() or b.behaviour->first().oclIsKindOf(OptionalBehaviour)).behaviour->first(), + let initial = self.block.behaviour->first(), targetComponent = Set{} - ->union(initials->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component) - ->union(initials->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance) - -> union(initials->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance), - optionalBlocks = self.block->closure( - b | b.behaviour->select(oclIsKindOf(SingleCombinedBehaviour)).oclAsType(SingleCombinedBehaviour).block - ->union(b.behaviour->select(oclIsKindOf(MultipleCombinedBehaviour)).oclAsType(MultipleCombinedBehaviour).block) - )->select(oclIsKindOf(OptionalBehaviour)) + ->including(initial->select(oclIsKindOf(Interaction)).oclAsType(Interaction).target.targetGate.component) + ->including(initial->select(oclIsKindOf(Quiescence)).oclAsType(Quiescence).componentInstance) + -> including(initial->select(oclIsKindOf(TimeOut)).oclAsType(TimeOut).componentInstance) in - optionalBlocks->isEmpty() - or optionalBlocks->first().oclAsType(Interaction).sourceGate.component->forAll(c | targetComponent->includes(c)) - or not self.getParentTestDescription().isLocallyOrdered + self.block.behaviour->select(oclIsKindOf(OptionalBehaviour)) .oclAsType(OptionalBehaviour).block + ->first().oclAsType(Interaction).sourceGate.component->forAll(c | targetComponent->includes(c)) + or not self.getParentTestDescription().isLocallyOrdered @@ -755,13 +781,13 @@ context AlternativeBehaviour context ConditionalBehaviour -- Guard for 'ConditionalBehaviour' with single block inv ConditionalFirstGuard ('If there is only one \'Block\' specified, it shall have a \'guard\'.' + self.toString()): - self.block->size() > 1 or self.block->first().guard->size() > 0 + self.block->size() > 1 or self.block->first().guard->size() > 1 -- Possible else block for 'ConditionalBehaviour' with multiple blocks inv ConditionalLastGuard ('All \'Block\'s specified, except the last one, shall have a \'guard\'.' + self.toString()): self.block->size() = 1 - or self.block->forAll(b | b = self.block->last() or b.guard ->size() > 1) + or self.block->forAll(b | b = self.block->last() or b.guard ->size() > 0) @@ -1093,7 +1119,7 @@ context TestDescriptionReference self.componentInstanceBinding->one(c | c.formalComponent = b.formalComponent or c.actualComponent = b.actualComponent)) - + -- Compatible test configurations inv CompatibleConfiguration ('The \'TestConfiguration\' of the referenced (invoked) \'TestDescription\' shall be compatible with the \'TestConfiguration\' of the referencing (invoking) \'TestDescription\' under the provided \'ComponentInstanceBinding\'s between the \'ComponentInstance\'s of the \'TestConfiguration\'s of referenced and referencing \'TestDescription\'s. ' + self.toString()): self.componentInstanceBinding->isEmpty()