tdl-generated-ETSI-ES-203-119-1-V1.5.1-fixed.evl 80.8 KB
Newer Older
import "../library/common.eol";
import "../library/helper.eol";
import "../library/debug.eol";

context Element {
  //[There are no constraints specified.]
}

context NamedElement {
  //Mandatory name
  constraint MandatoryName {
    check:     not self.name.oclIsUndefined() and self.name.size() > 0
    message:   self.prefix() + 
               "A 'NamedElement' shall have the 'name' property set and the 'name' shall be not an empty String."
  }

  //Distinguishable qualified names
  constraint DistinquishableName {
    check:     NamedElement.allInstances()->one(e | e.qualifiedName = self.qualifiedName)
    message:   self.prefix() + 
               "All qualified names of instances of 'NamedElement's shall be distinguishable within a TDL model."
  }

  //[NOTE:	It is up to the concrete syntax definition and tooling to resolve any name clashes between instances of the same meta-class in the qualified name.]
}

context PackageableElement {
  //[There are no constraints specified.]
}

context Package {
  //No cyclic imports
  constraint CyclicImports {
    check:     self.`import`->asOrderedSet()->closure(i | i.importedPackage.`import`)->forAll(i | 
              i.importedPackage <> self)
    message:   self.prefix() + 
               "A 'Package' shall not import itself directly or indirectly."
  }

}

context ElementImport {
  //Consistency of imported elements
  constraint ConsistentImports {
    check:     self.importedElement->forAll(e | self.importedPackage.packagedElement->includes(e))
    message:   self.prefix() + 
               "All imported 'PackageableElement's referenced by an 'ElementImport' shall be directly owned by the imported 'Package'."
  }

  //[Figure 5.2: Miscellaneous elements]
}

context Comment {
  //No nested comments
  constraint CommentNestedComments {
    check:     self.comment->isEmpty()
    message:   self.prefix() + 
               "A 'Comment' shall not contain 'Comment's."
  }

  //No annotations to comments
  constraint CommentNestedAnnotations {
    check:     self.annotation->isEmpty()
    message:   self.prefix() + 
               "A 'Comment' shall not contain 'Annotation's."
  }

}

context Annotation {
  //No nested annotations
  constraint AnnotationNestedAnnotations {
    check:     self.annotation->isEmpty()
    message:   self.prefix() + 
               "An 'Annotation' shall not contain 'Annotation's"
  }

  //No comments to annotations
  constraint AnnotationNestedComments {
    check:     self.comment->isEmpty()
    message:   self.prefix() + 
               "An 'Annotation' shall not contain 'Comment's."
  }

}

context AnnotationType {
  //[There are no constraints specified.]
}

context TestObjective {
  //[There are no constraints specified.]
}

context Extension {
  //Inherit from element of the same meta-class
  constraint Extension {
    check:     self.container().oclType() == self.extending.oclType() //TODO: corrected
    message:   self.prefix() + 
               "The element containing an 'Extension' and the element in the 'extending' property shall have the same meta-class."
  }

}

context ConstraintType {
  //[There are no constraints specified.]
}

context Constraint {
  //Effectively static quantifiers 
  constraint StaticQuantifiers {
    check:     self.quantifier.forAll(q | q.isEffectivelyStatic()) //TODO: Typo (quantifier vs quantifer)
    message:   self.prefix() + 
               "All 'DataUse's specified as 'quantifier's shall be effectively static."
  }

  //Empty arguments for quantifiers 
  constraint StaticQuantifiers {
    check:     self.quantifier.forAll(q | q.argument.isEmpty()) //TODO: Typo (quantifier vs quantifer)
    message:   self.prefix() + 
               "The 'argument' sets for all 'DataUse's specified as 'quantifier's shall be empty."
  }

  //Constraint applicability for 'union' and 'uniontype' 
  constraint ConstraintApplicabilityUnionUniontype {
    check:     (self.type.name = 'union' or self.type.name = 'uniontype') 
          implies self.container().oclIsTypeOf(StructuredDataType)
    message:   self.prefix() + 
               "The predefined 'ConstraintType's 'union' and 'uniontype' shall be applied to 'StructuredDataType's only. "
  }

  //Constraint applicability for 'range' and 'format'
  constraint ConstraintApplicabilityRangeFormat {
    check:     (self.type.name = 'range' or self.type.name = 'format') 
          implies (self.container().oclIsTypeOf(SimpleDataType)
             or (self.container().oclIsTypeOf(Member) 
                 and self.container().oclAsTypeOf(Member).dataType.oclIsTypeOf(SimpleDataType)))
    message:   self.prefix() + 
               "The predefined 'ConstraintType's 'range' and 'format' shall be applied to 'SimpleDataType's and 'Member's with a 'SimpleDataType' 'dataType' only. "
  }

  //Constraint applicability for 'length', 'minLength', and 'maxLength' 
  constraint ConstraintApplicabilityLength {
    check:     (self.type.name = 'length' or self.type.name = 'minLength' or self.type.name = 'maxLength')
          implies (self.container().oclIsTypeOf(SimpleDataType)
              or self.container().oclIsTypeOf(CollectionDataType)
              or (self.container().oclIsTypeOf(Member) 
                 and self.container().oclAsTypeOf(Member).dataType.oclIsTypeOf(SimpleDataType))
                 and self.container().oclAsTypeOf(Member).dataType.oclIsTypeOf(CollectionDataType)) //TODO: too many parentheses
    message:   self.prefix() + 
               "The predefined 'ConstraintType's 'length', 'minLength', and 'maxLength' shall be applied to 'CollectionDataType's, 'SimpleDataType's and 'Member's with a 'SimpleDataType' or a 'CollectionDataType' 'dataType' only. "
  }

  //Quantifiers for 'length', 'minLength', and 'maxLength'
  constraint ConstraintQuantifierLength {
    check:     (self.type.name = 'length' or self.type.name = 'minLength' or self.type.name = 'maxLength') 
          implies (self.quantifier->size() = 1 
              and self.quantifier->forAll(q | q.resloveDataType().conformsTo('Integer')))
    message:   self.prefix() + 
               "The predefined 'ConstraintType's 'length', 'minLength', and 'maxLength' shall be used with exactly one 'quantifier' resolved to an instance conforming to the predefined 'Integer' 'DataType'. "
  }

  //Quantifiers for 'range' 
  constraint ConstraintQuantifierRange {
    check:     (self.type.name = 'length') 
          implies (self.quantifier->size() = 2 
              and self.quantifier->forAll(q | q.resloveDataType().conformsTo('Integer')))
    message:   self.prefix() + 
               "The predefined 'ConstraintType' 'range' shall be used with exactly two 'quantifier's resolved to instance conforming to the predefined 'Integer' 'DataType'. "
  }

}

context DataResourceMapping {
  //[There are no constraints specified.]
}

context MappableDataElement {
  //[There are no constraints specified.]
}

context DataElementMapping {
  //Restricted use of 'ParameterMapping'
  constraint ParameterMappingType {
    check:     self.parameterMapping->size() = 0
      or (self.mappableDataElement.oclIsTypeOf(StructuredDataType) 
      and self.parameterMapping->forAll(p | 
               self.mappableDataElement.allMembers()->includes(p.parameter))) 
      or (self.mappableDataElement.oclIsKindOf(Action) 
      and self.parameterMapping->forAll(p | 
               self.mappableDataElement.formalParameter->includes(p.parameter)))
    message:   self.prefix() + 
               "A set of 'ParameterMapping's may only be provided if 'mappableDataElement' refers to a 'StructuredDataType', an 'Action' or a 'Function' definition and the 'mappableDataElement' contains the mapped 'Parameters'."
  }

  //All parameters shall be mapped
  constraint ParameterMappingType {
    check:     (self.mappableDataElement.oclIsTypeOf(SimpleDataType)
      or self.mappableDataElement.oclIsTypeOf(CollectionDataType) //TODO: added CollectionDataType exclusion
      or self.mappableDataElement.oclIsTypeOf(DataInstance)//TODO: added DataInstance exclusion
      or (self.mappableDataElement.oclIsTypeOf(StructuredDataType)
      and self.mappableDataElement.member->forAll(p | //TODO: allMembers()? 
               self.parameterMapping->exists(m | m.parameter = p)))
      or (self.mappableDataElement.oclIsKindOf(Action) 
      and self.mappableDataElement.formalParameter->forAll(p | 
               self.parameterMapping->exists(m | m.parameter = p)))
//      and self.parameterMapping->forAll(p |  //TODO: wrong condition
//               self.mappableDataElement.formalParameter->includes(p.parameter))
               )
    message:   self.prefix() + 
               "If the 'mappableDataElement' refers to a 'StructuredDataType', an 'Action' or a 'Function' definition, all the 'Parameters' contained in the 'mappableDataElement' shall be mapped."
  }

}

context ParameterMapping {
  //[There are no constraints specified.]
  //[Figure 6.2: Basic data concepts and simple data]
}

context DataType {
  //[There are no constraints specified.]
}

context DataInstance {
  //[There are no constraints specified.]
}

context SimpleDataType {
  //[There are no constraints specified.]
}

context SimpleDataInstance {
  //SimpleDataInstance shall refer to SimpleDataType
  constraint SimpleDataInstanceType {
    check:     self.dataType.oclIsKindOf(SimpleDataType)
    message:   self.prefix() + 
               "The inherited reference 'dataType' from 'DataInstance' shall refer to instances of 'SimpleDataType' solely."
  }

  //[Figure 6.3: Structured data type and instance]
}

context StructuredDataType {
  //Different member names in a structured data type
  constraint DistinguishableMemberNames {
    check:     self.allMembers()->forAll(e | self.allMembers()->one(m | m.name = e.name)) //TODO: Replaced due to lack of isUniquie implementation
//    check:     self.allMembers()->isUnique(e | e.name)
    message:   self.prefix() + 
               "All 'Member' names of a 'StructuredDataType' (including the names of inherited 'Members') shall be distinguishable."
  }

}

context Member {
  //[There are no constraints specified.]
}

context StructuredDataInstance {
  //StructuredDataInstance shall refer to StructuredDataType
  constraint StructuredDataInstance {
    check:     self.dataType.oclIsTypeOf(StructuredDataType)
    message:   self.prefix() + 
               "The inherited reference 'dataType' from 'DataInstance' shall refer to instances of 'StructuredDataType' solely."
  }

  //'Member' of the 'StructuredDataType'
  constraint ExistingMemberOfDataType {
    check:     self.memberAssignment->forAll(a | self.dataType.allMembers()->includes(a.member))
    message:   self.prefix() + 
               "The referenced 'Member' shall be contained in or inherited by the 'StructuredDataType' that the 'StructuredDataInstance', which contains this 'MemberAssignment', refers to."
  }

  //Unique assignments for each 'Member' of the 'StructuredDataType'
  constraint UniqueMemberAssignments {
    check:     self.memberAssignment->forAll(e | self.memberAssignment->one(m | m.member = e.member)) //TODO: Replaced due to lack of isUniquie implementation
//    check:     self.memberAssignment->isUnique(m | m.member)
    message:   self.prefix() + 
               "There shall be at most one 'memberAssignment' for each 'Member' of the 'StructuredDataType' that the 'StructuredDataInstance', which contains this 'MemberAssignment', refers to."
  }

  //'union' constraint on the type of the 'StructuredDataInstance'
  constraint StructuredDataInstanceUnionConstraint {
    //TODO: check if there is till a problem
    check:     not self.dataType.allConstraints()->exists(c | c.type.name = 'union')  //TODO: add ()
          or self.memberAssignment->size() <= 1
    message:   self.prefix() + 
               "If the 'dataType' of the 'StructuredDataInstance' has the predefined constraint 'union' then the 'memberAssignment' shall not contain more than one 'MemberAssignment'."
  }

  //'uniontype' constraint on the type of the 'StructuredDataInstance'
  constraint StructuredDataInstanceUniontypeConstraint {
    check:     not self.dataType.allConstraints()->exists(c | c.type.name = 'uniontype') //TODO: add ()
    //TODO: condition needed to be revised
          or self.memberAssignment->collect(m | m.member.container())->excluding(self.dataType)->size() < 2
//          or self.memberAssignment->forAll(m | self.dataType.oclAsType(StructuredDataType).member->includes(m.member) //TODO: fix . to ->; contains -> includes; m -> m.member; add oclAstType(StructuredDataType)
//              or self.dataType.oclAsType(StructuredDataType).extension->one(e | 
//                  e.extending.oclAsType(StructuredDataType).allMembers()->includes(m.member))) //TODO: fix contains -> includes; m -> m.member; add oclAstType(StructuredDataType)
    message:   self.prefix() + 
               "If the 'dataType' of 'StructuredDataInstance' has the predefined constraint 'uniontype' then there shall only be 'MemberAssignment' for the 'Member's of the 'dataType' itself or of at most one of the 'StructuredDataType's which the 'dataType' is extending."
  }

}

context MemberAssignment {
  //Type of a 'memberSpec' shall conform to the type of the 'member'
  constraint MatchingMemberDataType {
    check:     self.memberSpec.resolveDataType().conformsTo(self.member.dataType)
    message:   self.prefix() + 
               "The 'DataType' of the 'DataUse' of 'memberSpec' shall conform to the 'DataType' of the 'Member' of the 'MemberAssignment'."
  }

  //Restricted use of 'OmitValue' for optional 'Member's only
  constraint OmitValueUse {
    check:     (self.memberSpec.oclIsTypeOf(OmitValue) or self.memberSpec.oclIsTypeOf(AnyValueOrOmit))
          implies self.member.isOptional = true
    message:   self.prefix() + 
               "A non-optional 'Member' shall have a 'DataUse' specification assigned to it that is different from 'OmitValue' and 'AnyValueOrOmit'."
  }

  //Static data use in 'memberSpec' 
  constraint StaticDataInMemberSpec {
    check:     self.memberSpec.isEffectivelyStatic()
    message:   self.prefix() + 
               "The 'memberSpec' and all of its 'ParameterBinding's shall be effectively static. "
  }

  //[Figure 6.4: Collection data]
}

context CollectionDataType {
  //No multidimensional collections
  constraint NoMultidimensionalCollections {
    check:     not self.itemType.oclIsKindOf(CollectionDataType)
    message:   self.prefix() + 
               "The 'itemType' shall not be an instance of 'CollectionDataType'. "
  }

}

context CollectionDataInstance {
  //CollectionDataInstance shall refer to CollectionDataType
  constraint  CollectionDataInstanceType {
    check:     self.dataType.oclIsKindOf(CollectionDataType)
    message:   self.prefix() + 
               "The inherited reference 'dataType' from 'DataInstance' shall refer to instances of 'CollectionDataType' solely."
  }

  //Type of items in the 'CollectionDataInstance'
  constraint CollectionDataInstanceItemType {
    check:     self.item.forAll(i | 
              not i.resolveDataType().oclIsUndefined() implies //TODO: workaround for some strange bug with resolveDataType().. 
              i.resolveDataType().conformsTo(self.dataType.oclAsType(CollectionDataType).itemType))
    message:   self.prefix() + 
               "The items in 'CollectionDataInstance' shall conform to the 'itemType' of the 'CollectionDataType' that is defined as the 'dataType' of this 'CollectionDataInstance'. "
  }

  //Static data use in 'item' 
  constraint StaticDataInItem {
    check:     self.item.forAll(i | i.isEffectivelyStatic())
    message:   self.prefix() + 
               "The DataUse's in 'item' and all of the respective 'ParameterBinding's shall be effectively static. "
  }

  //Length constraint of the 'CollectionDataInstance'
  constraint CollectionDataInstanceLengthConstraint {
    check:     true //This constraint cannot be expressed formally.
    message:   self.prefix() + 
               "If the 'dataType' 'CollectionType' contains the predefined constraint 'length' then the length of this 'CollectionDataInstance' shall be equal to the 'quantifier' of that 'Constraint'."
  }

  //[Figure 6.5: Procedure and procedure parameter]
}

context ProcedureSignature {
  //[There are no constraints specified.]
}

context ProcedureParameter {
  //[There are no constraints specified.]
}

//TODO: enums shall be excluded
//context ParameterKind {
//  //[There are no constraints specified.]
//  //[Figure 6.6: Action, function, parameter and variable]
//}

context Parameter {
  //[There are no constraints specified.]
}

context FormalParameter {
  //[There are no constraints specified.]
}

context Variable {
  //[There are no constraints specified.]
}

context Action {
  //[There are no constraints specified.]
}

context Function {
  //[There are no constraints specified.]
}

//TODO: enums shall be excluded
//context UnassignedMemberTreatment {
//  //[There are no constraints specified.]
//}

context PredefinedFunction {
  //[There are no constraints specified.]
}

context EnumDataType {
  //SimpleDataInstance container in EnumDataType
  constraint  EnumDataInstanceContainment {
//    check:     OclInvalid() ////TODO: Not specified in draft, probably better put under SimpleDataInstance? or redundant?
    check:     self.value->forAll(v | v.dataType.oclIsKindOf(EnumDataType) and v.dataType = self)
    message:   self.prefix() + 
               "A 'SimpleDataInstance' whose 'dataType' property refers to an 'EnumDataType' shall be contained in that 'EnumDataType'."
  }

  //TODO: obsolete! 
  //No extensions for EnumDataType
//  constraint  EnumDataTypeExtensions {
//    check:     OclInvalid() //self.extension.oclIsUndefined() //TODO: Not specified in draft -> no longer applicable
//    message:   self.prefix() + 
//               "The 'extension' property of an 'EnumDataType' shall be empty."
//  }

}

context DataUse {
  //Occurrence of 'argument' and 'reduction'
  constraint ArgumentReductionLists {
    check:     self.argument.isEmpty() or self.reduction.isEmpty() or self.oclIsTypeOf(FunctionCall)
    message:   self.prefix() + 
               "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."
  }

  //Structured data types in 'reduction' set
  constraint ReductionMembers {
    check:     //not self.resolveDataType().oclIsUndefined() implies //TODO: figure out why this strange bug happens with self.resolveDataType, consider debugging further self.debugPassthrough("DU").debugRM() and
               not self.resolveDataType().isKindOf(StructuredDataType)
      or self.reduction->isEmpty()
      or self.resolveDataType().allMembers()->includes(self.reduction->first().member)
      and self.reduction->select(m | self.reduction->indexOf(m) > 0)->forAll(m |
      //TODO: handle edge cases - first reduction, reduction on collection
              (self.reduction->at(self.reduction->indexOf(m)-1).member.oclIsUndefined() and
              (self.resolveDataType().isKindOf(StructuredDataType) and self.resolveDataType().allMembers()->includes(m.member)) or
              (self.resolveDataType().isKindOf(CollectionDataType) and self.resolveDataType().itemType.allMembers()->includes(m.member))
              ) or
              (self.reduction->at(self.reduction->indexOf(m)-1).member.dataType.isKindOf(StructuredDataType)
          and self.reduction->at(self.reduction->indexOf(m)-1).member.dataType.allMembers()
      ->includes(m.member)))
    message:   self.prefix() + 
               "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'."
  }

  //No member with collection index in the first element in reduction
  constraint FirstReduction {
    check:     self.reduction->first().oclIsUndefined() //TODO: add additional condition
          or self.reduction->first().member.oclIsUndefined() or self.reduction->first().collectionIndex.oclIsUndefined()
    message:   self.prefix() + 
               "The first 'MemberReference' in reduction shall not specify both member and collectionIndex. "
  }

}

context ParameterBinding {
  //Matching data type
  constraint ParameterBindingTypes {
    check:     self.dataUse.resolveDataType().conformsTo(self.parameter.dataType)
    message:   self.prefix() + 
               "The provided 'DataUse' shall conform to the 'DataType' of the referenced 'Parameter'."
  }

  //Use of a 'StructuredDataInstance' with non-optional 'Member's
  constraint OmitValueParameter {
    check:     self.parameter.oclIsTypeOf(Member) and self.parameter.oclAsType(Member).isOptional = false
             implies not self.dataUse.oclIsTypeOf(OmitValue) and not self.dataUse.oclIsTypeOf(AnyValueOrOmit)
    message:   self.prefix() + 
               "A non-optional 'Member' of a 'StructuredDataType' shall have a 'DataUse' specification assigned to it that is different from 'OmitValue' or 'AnyValueOrOmit'."
  }

}

context MemberReference {
  //Collection index expressions for collections only
  constraint CollectioinIndex {
    check:     self.collectionIndex.oclIsUndefined()
              or self.container().oclAsType(DataUse).resolveDataType().oclIsKindOf(CollectionDataType)
    message:   self.prefix() + 
               "If the type of the related 'DataUse' is not 'CollectionDataType' then the collectionIndex shall be undefined. "
  }

  //Either member or collection index is required
  constraint MemberOrReduction {
    check:     not self.member.oclIsUndefined() or not self.collectionIndex.oclIsUndefined()
    message:   self.prefix() + 
               "Either the member or collectionIndex shall be specified. "
  }

}

context StaticDataUse {
  //[There are no constraints specified.]
}

context DataInstanceUse {
  //'DataInstance' reference or non-empty 'argument' or non-empty 'item'
  constraint DataInstanceOrArgumentsOrItems {
    check:     not self.dataInstance.oclIsUndefined() or not self.argument->isEmpty() or not self.item->isEmpty()
    message:   self.prefix() + 
               "If a 'dataInstance' is not specified, either a non-empty 'argument' set or a non-empty 'item' set shall be specified."
  }

  //Valid 'DataType' for items
  constraint DataTypeOfItemsInDataInstance {
    check:     self.item.forAll(i | i.resolveDataType().conformsTo(self.resolveDataType().oclAsType(CollectionDataType).itemType))
    message:   self.prefix() + 
               "The items in the 'item' property shall conform to the 'itemType' of the resolved 'CollectionDataType'."
  }

  //No 'item' if 'dataInstance' is specified
  constraint NoItemWithDataInstance {
    check:     not self.dataInstance.oclIsUndefined() and self.item->isEmpty()
    message:   self.prefix() + 
               "The 'item' property shall be empty if the 'dataInstance' property is specified."
  }

}

context SpecialValueUse {
  //Empty 'argument' and 'reduction' sets
  constraint SpecialValueArgumentReduction {
    check:     self.reduction->isEmpty() and self.argument->isEmpty()
    message:   self.prefix() + 
               "The 'argument' and 'reduction' sets shall be empty."
  }

}

context AnyValue {
  //[There are no constraints specified.]
}

context AnyValueOrOmit {
  //[There are no constraints specified.]
}

context OmitValue {
  //[There are no constraints specified.]
  //[Figure 6.8: Dynamic data use]
}

context DynamicDataUse {
  //[There are no constraints specified.]
}

context FunctionCall {
  //Matching parameters
  constraint FunctionCallParameters {
    check:     self.`function`.formalParameter->forAll(p | self.argument->exists(a | a.parameter = p))
    message:   self.prefix() + 
               "All 'FormalParameter's of the invoked 'Function' shall be bound."
  }

}

context FormalParameterUse {
  //[There are no constraints specified.]
}

context VariableUse {
  //Local variables of tester components only
  constraint VariableUseComponentRole {
    //TODO: Enum::Literal not supported -> use Enum#Literal
    check:     self.componentInstance.type.allVariables()->includes(self.variable)  
          and self.componentInstance.role = ComponentInstanceRole#Tester
    message:   self.prefix() + 
               "All variables used in a 'DataUse' specification via a 'VariableUse' shall be local to the same 'componentInstance' and the 'componentInstance' shall be in the role 'Tester'."
  }

}

context PredefinedFunctionCall {
  //Compatible actual parameters
  constraint PredefinedFunctionCallParameters {
    check:     true //This constraint cannot be expressed formally.
    message:   self.prefix() + 
               "The number and type of actual parameters shall be compatible with the formal parameters of the invoked 'PredefinedFunction' according to the specification of the 'PredefinedFunction'."
  }

  //Empty 'argument' and 'reduction' sets
  constraint PredefinedFunctionCallArgumentReduction {
    check:     self.reduction->isEmpty() and self.argument->isEmpty()
    message:   self.prefix() + 
               "The 'argument' and 'reduction' sets shall be empty."
  }

}

context LiteralValueUse {
  //Exactly one value specification
  constraint SpecifiedLiteralValue {
    check:     not self.value.oclIsUndefined() 
          xor not self.intValue.oclIsUndefined() 
          xor not self.boolValue.oclIsUndefined()
    message:   self.prefix() + 
               "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."
  }

  //Empty 'argument' and 'reduction' sets if not 'dataType'
  constraint LiteralValueArgumentReduction {
    check:     (self.dataType.oclIsUndefined()) 
              implies (self.reduction->isEmpty() and self.argument->isEmpty())
    message:   self.prefix() + 
               "If 'dataType' is not specified then the 'argument' and 'reduction' sets shall be empty."
  }

  //Integer type for integer value
  constraint LiteralValueIntType {
    check:     not self.intValue.oclIsUndefined() //TODO: weird caching issues..
          implies (self.dataType.oclIsUndefined() or self.dataType.conformsTo('Integer'))
    message:   self.prefix() + 
               "If 'intValue' is specified then the 'dataType' is either unspecified or the specified 'DataType' conforms to predefined type 'Integer'."
  }

  //Boolean type for Boolean value
  constraint LiteralValueBoolType {
    check:     not self.boolValue.oclIsUndefined() //TODO: copy-paste error - intValue -> boolValue 
          implies (self.dataType.oclIsUndefined() or self.dataType.conformsTo('Boolean'))
    message:   self.prefix() + 
               "If 'boolValue' is specified then the 'dataType' is either unspecified or the specified 'DataType' conforms to predefined type 'Boolean'."
  }

}

context DataElementUse {
  //'DataElement' reference or non-empty 'argument' or non-empty 'item'
  constraint DataInstanceOrArgumentsOrItemsInDataElementUse {
    check:     not (self.dataElement.oclIsUndefined() and self.argument->isEmpty() and self.item->isEmpty())
          and not (self.dataElement.oclIsKindOf(StructuredDataType) and self.argument->isEmpty())
          and not (self.dataElement.oclIsKindOf(CollectionDataType) and self.item->isEmpty())
    message:   self.prefix() + 
               "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."
  }

  //Valid 'DataType' for items
  constraint DataTypeOfItemsInDataInstance {
  //TODO: check why this fails still with datainstanceuse
    check:     self.item.forAll(i | i
                .resolveDataType()
                .conformsTo(self.resolveDataType().oclAsType(CollectionDataType).itemType))
    message:   self.prefix() + 
               "The items in the 'item' property shall conform to the 'itemType' of the resolved 'CollectionDataType'."
  }

  //Only 'item' if the resolved data type is 'CollectionDataType'
  constraint ItemOnlyWithCollectionDataType {
    //TODO: add missing parenthesis
    check:     (((self.dataElement.oclIsKindOf(CollectionDataType))
      or self.dataElement.oclIsUndefined())
      and not self.item->isEmpty())
      or self.item->isEmpty()
    message:   self.prefix() + 
               "The 'item' property shall be non-empty if the 'dataElement' property is resolved to a 'CollectionDataType'."
  }

  //Matching parameters for 'Function's
  constraint FunctionCallParameters {
    check:     not self.dataElement.oclIsKindOf(Function)
      or self.dataElement.oclAsType(Function).formalParameter->forAll(p | self.argument->exists(a | a.parameter = p))
    message:   self.prefix() + 
               "All 'FormalParameter's shall be bound if the 'dataElement' refers to a a 'Function'."
  }

}

context Time {
  //[There are no constraints specified.]
}

context TimeLabel {
  //[There are no constraints specified.]
}

context TimeLabelUse {
  //Empty 'argument' and 'reduction' sets
  constraint TimeLabelArgumentReduction {
    check:     self.reduction->isEmpty() and self.argument->isEmpty()
    message:   self.prefix() + 
               "The 'argument' and 'reduction' sets shall be empty."
  }

  //'TimeLabel's only within the same 'TestDescription' when local ordering is used 
  constraint TimeLabelLocallyOrdered {
    check:     self.getParentTestDescription.isLocallyOrdered = true
      or self.timeLabel.getParentTestDescription() = self.getParentTestDescription()
    message:   self.prefix() + 
               "When local ordering is used, 'TimeLabel's shall only be used within the same test description. "
  }

}

//TODO: ignore enumerations
//context TimeLabelUseKind {
//  //[There are no constraints specified.]
//}

context TimeConstraint {
  //Time constraint expression of type Boolean
  constraint TimeConstraintType {
    check:     self.timeConstraintExpression.resolveDataType().name = 'Boolean'
    message:   self.prefix() + 
               "The expression given in the 'DataUse' specification shall evaluate to predefined type 'Boolean'."
  }

  //Use of local variables only
  constraint TimeConstraintVariables {
    check:     self.timeConstraintExpression.argument
              ->closure(a | a.dataUse.argument)->collect(pb | pb.dataUse)
              ->includingAll(self.timeConstraintExpression.argument) //TODO: remove extra parethesis, includingAll instead of union
              ->select(du | du.oclIsKindOf(VariableUse))
              ->forAll(du | self.container().getParticipatingComponents().includes(
                  du.oclAsType(VariableUse).componentInstance))
    message:   self.prefix() + 
               "The expression given in the 'DataUse' specification shall contain only 'Variable's that are local to the 'AtomicBehaviour' that contains this 'TimeConstraint'. That is, all 'VariableUse's shall reference the 'ComponentInstance's which participate in the 'AtomicBehaviour'."
  }

  //Use of local time labels only
  constraint TimeConstraintTimeLabels {
    check:     self.timeConstraintExpression.argument
              ->closure(a | a.dataUse.argument)->collect(pb | pb.dataUse)
              ->includingAll(self.timeConstraintExpression.argument) //TODO: remove extra parethesis //TODO: replacing union
              ->select(du | du.oclIsKindOf(TimeLabelUse))
              ->forAll(du | self.container().getParticipatingComponents().includesAll(
                  du.oclAsType(TimeLabelUse).timeLabel.container().getParticipatingComponents()))
    message:   self.prefix() + 
               "In case of locally ordered 'TestDescription', the expression given in the 'DataUse' specification shall contain only 'TimeLabel's that are local to the 'AtomicBehaviour' that contains this 'TimeConstraint'. That is, all 'TimeLabel's shall be contained in 'AtomicBehaviour's involving the 'ComponentInstance's which participate in the 'AtomicBehaviour' that contains this 'TimeConstraint."
  }

  //[Figure 7.2: Time operations]
}

context TimeOperation {
  //Component required in locally ordered test description
  constraint TimeOperationComponent {
    check:     self.getParentTestDescription.isLocallyOrdered 
          implies not self.componentInstance.oclIsUndefined()
    message:   self.prefix() + 
               "If the 'TimeOperation' is contained in a locally ordered 'TestDescription' then the 'componentInstance' shall be specified."
  }

  //Time operations on tester components only
  constraint TimeOperationComponentRole {
    //TODO: Enum::Literal not supported -> use Enum#Literal
    check:     (not self.componentInstance.oclIsUndefined()
           and self.componentInstance.role = ComponentInstanceRole#Tester)
      or (self.oclIsTypeOf(Quiescence)
           and not self.gateReference.oclIsUndefined()
           and self.gateReference.component.role.name = ComponentInstanceRole#Tester)
    message:   self.prefix() + 
               "A 'TimeOperation' shall be performed only on a 'ComponentInstance' in the role 'Tester'."
  }

  //'Time' data type for period expression
  constraint TimePeriodType {
    check:     self.period.resolveDataType().oclIsKindOf(Time)
    message:   self.prefix() + 
               "The 'DataUse' expression assigned to the 'period' shall evaluate to a data instance of the 'Time' data type."
  }

}

context Wait {
  //[There are no constraints specified.]
}

context Quiescence {
  //Exclusive use of gate reference or component instance
  constraint QuiescenceTarget {
    check:     self.gateReference.oclIsUndefined() xor self.componentInstance.oclIsUndefined()
    message:   self.prefix() + 
               "If a 'GateReference' is provided, a 'ComponentInstance' shall not be provided and vice versa."
  }

  //[Figure 7.3: Timer and timer operations]
}

context Timer {
  //[There are no constraints specified.]
}

context TimerOperation {
  //Timer operations on tester components only
  constraint TimerOperationComponentRole {
    //TODO: Enum::Literal not supported -> use Enum#Literal
    check:     self.componentInstance.role = ComponentInstanceRole#Tester
    message:   self.prefix() + 
               "A 'TimerOperation' shall be performed only on a 'ComponentInstance' in the role 'Tester'."
  }

}

context TimerStart {
  //'Time' data type for period expression
  constraint TimerPeriodType {
    check:     self.period.resolveDataType().oclIsKindOf(Time)
    message:   self.prefix() + 
               "The 'DataUse' expression assigned to the 'period' shall evaluate to a data instance of the 'Time' data type."
  }

}

context TimerStop {
  //[There are no constraints specified.]
}

context TimeOut {
  //[There are no constraints specified.]
}

context GateType {
  //Compatible 'DataType's. 
  constraint GateType {
    //TODO: Enum::Literal not supported -> use Enum#Literal
    //use GateTypeKind#Procedure / GateTypeKind#Message self.kind.name = 'Procedure' / 'Message'
    //use GateTypeKind#Equals.eEnum.eLiterals.Procedure or self.kind.name = 'Procedure'
    check:     (self.kind = GateTypeKind#Procedure and self.allDataTypes()->forAll(t | //TODO: parentheses - no precedence in Epsilon!!!, also make use of implies
      t.oclIsTypeOf(ProcedureSignature)))
      or (self.kind = GateTypeKind#Message and self.allDataTypes()->forAll(t | t.oclIsTypeOf(StructuredDataType)
                  or t.oclIsKindOf(SimpleDataType) or t.oclIsTypeOf(CollectionDataType)))
    message:   self.prefix() + 
               "The 'DateType's specified for the 'GateType' shall correspond the kind of the 'GateType'. For 'GateType' of kind 'Procedure' only 'ProcedureSignature's shall be specified as data types. For 'GateType' of kind 'Message' only 'StructuredDataType's, 'SimpleDataType's and 'CollectionDataType's shall be specified as data types. "
  }

}

//TODO: enums shall be excluded
//context GateTypeKind {
//  //[There are no constraints specified.]
//}

context GateInstance {
  //[There are no constraints specified.]
}

context ComponentType {
  //[There are no constraints specified.]
  //[Figure 8.2: Test configuration]
}

context ComponentInstance {
  //[There are no constraints specified.]
}

//TODO: enums shall be excluded
//context ComponentInstanceRole {
//  //[There are no constraints specified.]
//}

context GateReference {
  //Gate instance of the referred component instance
  constraint GateInstanceReference {
    check:     self.component.type.allGates()->includes(self.gate)
    message:   self.prefix() + 
               "The referred 'GateInstance' shall be contained in the 'ComponentType' of the referred 'ComponentInstance'."
  }

}

context Connection {
  //Self-loop connections are not permitted
  constraint NoSelfLoop {
    check:     self.endPoint->forAll(e1 | self.endPoint->one(e2 | e1.gate = e2.gate
              and e1.component = e2.component))
    message:   self.prefix() + 
               "The 'endPoint's of a 'Connection' shall not be the same. Two endpoints are the same if both, the referred 'ComponentInstance's and the referred 'GateInstance's, are identical."
  }

  //Consistent type of a connection
  constraint ConsistentConnectionType {
    check:     self.endPoint->at(0).gate.type = self.endPoint->at(1).gate.type
    message:   self.prefix() + 
               "The 'GateInstance's of the two 'endPoint's of a 'Connection' shall refer to the same 'GateType'."
  }

}

context TestConfiguration {
  //'TestConfiguration' and components roles
  constraint ComponentRoles {
    //TODO: Enum::Literal not supported -> use Enum#Literal
    check:     self.componentInstance->exists(c | c.role = ComponentInstanceRole#Tester)
      and self.componentInstance->exists(c | c.role = ComponentInstanceRole#SUT)
    message:   self.prefix() + 
               "A 'TestConfiguration' shall contain at least one 'Tester' and one 'SUT' 'ComponentInstance'."
  }

  //Only 'Connection's between own 'ComponentInstance's 
  constraint OwnedComponents {
    check:     self.connection->forAll(c |
              self.componentInstance->includes(c.endPoint->at(0).component)
          and self.componentInstance->includes(c.endPoint->at(1).component))
    message:   self.prefix() + 
               "A 'TestConfiguration' shall only contain 'Connection's between gates of its own 'ComponentInstance's. "
  }

  //Minimal 'TestConfiguration'
  constraint MinimalTestConfiguration {
    //TODO: Enum::Literal not supported -> use Enum#Literal
    check:     self.connection->exists(c |
              (c.endPoint->at(0).component.role = ComponentInstanceRole#Tester
           and c.endPoint->at(1).component.role = ComponentInstanceRole#SUT)    
           or (c.endPoint->at(0).component.role = ComponentInstanceRole#SUT
           and c.endPoint->at(1).component.role = ComponentInstanceRole#Tester))
    message:   self.prefix() + 
               "Each 'TestConfiguration' shall specify at least one 'Connection' that connects a 'GateInstance' of a 'ComponentInstance' in the role 'Tester' with a 'GateInstance' of a 'ComponentInstance' in the role 'SUT'."
  }

  //At most one connection between any two 'GateInstance'/'ComponentInstance' pairs
  constraint UniqueConnections {
    check:     self.connection->forAll(c1 | self.connection->one(c2 |
              (c1.endPoint->at(0).component = c2.endPoint->at(0).component
           and c1.endPoint->at(0).gate = c2.endPoint->at(0).gate
           and c1.endPoint->at(1).component = c2.endPoint->at(1).component
           and c1.endPoint->at(1).gate = c2.endPoint->at(1).gate)
      
           or (c1.endPoint->at(1).component = c2.endPoint->at(0).component
           and c1.endPoint->at(1).gate = c2.endPoint->at(0).gate
           and c1.endPoint->at(0).component = c2.endPoint->at(1).component
           and c1.endPoint->at(0).gate = c2.endPoint->at(1).gate)))
    message:   self.prefix() + 
               "Given the set of 'Connection's contained in a 'TestConfiguration'. There shall be no two 'Connection's containing 'GateReference's that in turn refer to identical pairs of 'GateInstance'/'ComponentInstance'."
  }

}

context TestDescription {
  //[There are no constraints specified.]
}

context BehaviourDescription {
  //[There are no constraints specified.]
}

context Behaviour {
  //[There are no constraints specified.]
}

context Block {
  //Guard shall evaluate to Boolean
  constraint GuardType {
    check:     self.`guard`.oclIsUndefined() or self.`guard`->forAll(le | le.expression.resolveDataType().name = 'Boolean') //TODO: correct
//    check:     self.`guard`.oclIsUndefined() or self.`guard`.resolveDataType().name = 'Boolean'
    message:   self.prefix() + 
               "The type of 'guard' shall be 'Boolean'."
  }

  //No directly contained 'ExceptionalBehaviour's and 'PeriodicBehaviour's.
  constraint AllowedBehaviourTypes {
    check: self.behaviour.forAll(b |
         not b.oclIsTypeOf(ExceptionalBehaviour) and not b.oclIsTypeOf(PeriodicBehaviour))
    message:   self.prefix() + 
               "A 'Block' shall not contain 'ExceptionalBehaviour's and 'PeriodicBehaviour's."
  }

  //Guard for each participating tester in locally ordered test descriptions
  constraint GuardsForParticipatingComponents {
    //TODO: Enum::Literal not supported -> use Enum#Literal
    check:     (not self.`guard`.isEmpty() implies //TODO: constraint shall be relaxed when there are no guards
                self.getParticipatingComponents()->reject(c | c.role = ComponentInstanceRole#SUT)
              ->forAll(c | self.`guard`->exists(ex | ex.scope = c)) //TODO: renamed componentInstance to scope
          or not self.getParentTestDescription().isLocallyOrdered
    message:   self.prefix() + 
               "If the 'Block' is contained in a locally ordered 'TestDescription' then a guard shall be specified for every participating 'ComponentInstance' in the associated 'TestConfiguration' that has the role 'Tester' or there shall be no guards at all. "
  }

  //Single guard in totally ordered test description
  constraint SingleTotalGuard {
    check:     self.getParentTestDescription().isLocallyOrdered or self.`guard`->size() <= 1
    message:   self.prefix() + 
               "If the 'Block' is contained in a totally ordered 'TestDescription' then there shall not be more than one guard. "
  }

}

context LocalExpression {
  //Local expressions in locally ordered test descriptions have 'ComponentInstance' specified
  constraint LocalExpressionComponent {
    check:     self.getParentTestDescription().isLocallyOrdered 
          implies not self.scope.oclIsUndefined() //TODO: renamed componentInstance to scope
    message:   self.prefix() +