inv:
let
-- 1. Pre-calculate the container name (for readability and efficiency)
containerName : String = self.mediniGetContainer().oclAsType(safety::MeasureCatalog).name,
FMEDAName : String = self.mediniGetOpposites(null)->select(entry|entry.oclIsKindOf(safety::FailureMode))->collect(entry|entry.oclAsType(safety::FailureMode).mediniGetOpposites('element'))->flatten() ->select(entry|entry.oclIsKindOf(dc::DCFailureModeEntry))->collect(entry|entry.oclAsType(dc::DCFailureModeEntry).component.worksheet)->asSet()->collect(worksheet | worksheet.name) ->asSet()
in
let
-- 2. Pre-calculate the set of DCFailureModeEntry (for readability and efficiency)
dcFailureEntries : Set(dc::DCFailureModeEntry) =
self.mediniGetOpposites(null)->select(entry|entry.oclIsKindOf(safety::FailureMode))
->collect(entry|entry.oclAsType(safety::FailureMode).mediniGetOpposites('element'))
->flatten()
->select(entry|entry.oclIsKindOf(dc::DCFailureModeEntry))
->collect(entry|entry.oclAsType(dc::DCFailureModeEntry))
->asSet()
in
-- 3. Evaluate the conditional logic for the invariant
if containerName.matches('Rationales') then
true
else
if containerName.matches('Internal Safety Mechanisms') or
containerName.matches('External Safety Mechanisms')
then
-- Case 1: Container name matches a valid category.
let
MessageArg1 : String = 'Missing allocation: ',
MessageArg2 : String = containerName,
MessageArg3 : String = 'not allocated to any DC failure entry',
MessageArg4 : String = ''
in
dcFailureEntries->notEmpty()
else
-- Case 2: Container name does NOT match any valid category.
let
MessageArg1 : String = 'Wrong allocation: ',
MessageArg2 : String = containerName,
MessageArg3 : String = 'wrongly allocated to a DC failure mode but not part of valid catalog in following worksheet: ',
MessageArg4 : String = FMEDAName
in
dcFailureEntries->isEmpty()
endif
endif