diff --git a/.vscode/settings.json b/.vscode/settings.json index 81b05b3b..478df016 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -38,5 +38,13 @@ ], // Disable internal type checking, since we use basedpyright - "python.analysis.typeCheckingMode": "off" + "python.analysis.typeCheckingMode": "off", + "cSpell.words": [ + "ASIL", + "FMEA", + "isopas", + "isosae", + "stkh", + "workproduct" + ] } diff --git a/MODULE.bazel b/MODULE.bazel index 143e6af8..cae1f74c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -13,7 +13,7 @@ module( name = "score_docs_as_code", - version = "0.4.1", + version = "0.4.2", compatibility_level = 0, ) diff --git a/src/extensions/score_metamodel/checks/check_options.py b/src/extensions/score_metamodel/checks/check_options.py index ca675cd5..57e0c073 100644 --- a/src/extensions/score_metamodel/checks/check_options.py +++ b/src/extensions/score_metamodel/checks/check_options.py @@ -82,7 +82,10 @@ def remove_prefix(word: str, prefixes: list[str]) -> str: try: if not re.match(pattern, value): log.warning_for_option( - need, field, f"does not follow pattern `{pattern}`." + need, + field, + f"does not follow pattern `{pattern}`.", + new_check="ASIL_D" in value, ) except TypeError: log.warning_for_option( diff --git a/src/extensions/score_metamodel/checks/graph_checks.py b/src/extensions/score_metamodel/checks/graph_checks.py index dfa38fe9..ed914388 100644 --- a/src/extensions/score_metamodel/checks/graph_checks.py +++ b/src/extensions/score_metamodel/checks/graph_checks.py @@ -137,11 +137,9 @@ def check_metamodel_graph( # Convert list to dictionary for easy lookup needs_dict_all = {need["id"]: need for need in all_needs.values()} needs_local = list(all_needs.filter_is_external(False).values()) - # Iterate over all graph checks for check in graph_checks_global.items(): apply, eval = check[1].values() - # Get all needs that match the selection criteria selected_needs = get_need_selection(needs_local, apply, log) diff --git a/src/extensions/score_metamodel/metamodel.yaml b/src/extensions/score_metamodel/metamodel.yaml index fdc120a9..4aca501d 100644 --- a/src/extensions/score_metamodel/metamodel.yaml +++ b/src/extensions/score_metamodel/metamodel.yaml @@ -188,7 +188,7 @@ needs_types: id: ^doc__[0-9a-z_]*$ status: ^(valid|draft|invalid)$ optional_options: - safety: "^(QM|ASIL_B|ASIL_D)$" + safety: "^(QM|ASIL_B)$" security: "^(YES|NO)$" realizes: "^wp__.+$" @@ -201,7 +201,7 @@ needs_types: id: ^stkh_req__[0-9a-z_]*$ # req-Id: tool_req__docs_req_attr_reqtype reqtype: ^(Functional|Interface|Process|Legal|Non-Functional)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ # req-Id: tool_req__docs_req_attr_rationale rationale: ^.+$ @@ -225,7 +225,7 @@ needs_types: # req-Id: tool_req__docs_req_attr_reqtype reqtype: ^(Functional|Interface|Process|Legal|Non-Functional)$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ mandatory_links: # req-Id: tool_req__docs_req_link_satisfies_allowed @@ -248,7 +248,7 @@ needs_types: # req-Id: tool_req__docs_req_attr_reqtype reqtype: ^(Functional|Interface|Process|Legal|Non-Functional)$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ mandatory_links: # req-Id: tool_req__docs_req_link_satisfies_allowed @@ -269,7 +269,7 @@ needs_types: mandatory_options: id: ^tool_req__[0-9a-z_]*$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ optional_links: # req-Id: tool_req__docs_req_link_satisfies_allowed @@ -298,7 +298,7 @@ needs_types: # req-Id: tool_req__docs_req_attr_reqtype reqtype: ^(Functional|Interface|Process|Legal|Non-Functional)$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ optional_options: codelink: ^.*$ @@ -321,7 +321,7 @@ needs_types: mandatory_options: id: ^feat_arc_sta__[0-9a-z_]+$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ mandatory_links: includes: ^logic_arc_int(_op)*__.+$ @@ -336,7 +336,7 @@ needs_types: mandatory_options: id: ^feat_arc_dyn__[0-9a-z_]+$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ mandatory_links: fulfils: ^feat_req__.+$ @@ -349,7 +349,7 @@ needs_types: mandatory_options: id: ^logic_arc_int__[0-9a-z_]+$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ optional_links: includes: ^logic_arc_int_op__.+$ @@ -363,7 +363,7 @@ needs_types: mandatory_options: id: ^logic_arc_int_op__[0-9a-z_]+$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ mandatory_links: included_by: ^logic_arc_int__.+$ @@ -394,7 +394,7 @@ needs_types: mandatory_options: id: ^comp_arc_sta__[0-9a-z_]+$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ optional_links: implements: ^real_arc_int(_op)*__.+$ @@ -410,7 +410,7 @@ needs_types: mandatory_options: id: ^comp_arc_dyn__[0-9a-z_]+$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ optional_links: fulfils: ^comp_req__.+$ @@ -423,7 +423,7 @@ needs_types: mandatory_options: id: ^real_arc_int__[0-9a-z_]+$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ language: ^(cpp|rust)$ optional_links: @@ -437,7 +437,7 @@ needs_types: mandatory_options: id: ^real_arc_int_op__[0-9a-z_]+$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ mandatory_links: included_by: ^real_arc_int__.+$ @@ -463,7 +463,7 @@ needs_types: mandatory_options: id: ^dd_sta__[0-9a-z_]*$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ mandatory_links: implements: ^comp_req__.*$ @@ -479,7 +479,7 @@ needs_types: mandatory_options: id: ^dd_dyn__[0-9a-z_]*$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ mandatory_links: implements: ^comp_req__.*$ @@ -491,7 +491,7 @@ needs_types: mandatory_options: id: ^sw_unit__[0-9a-z_]*$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ sw_unit_int: title: Software unit interfaces @@ -501,9 +501,86 @@ needs_types: mandatory_options: id: ^sw_unit_int__[0-9a-z_]*$ security: ^(YES|NO)$ - safety: ^(QM|ASIL_B|ASIL_D)$ + safety: ^(QM|ASIL_B)$ status: ^(valid|invalid)$ + # Safety Analysis DFA + feat_plat_saf_dfa: + title: DFA + prefix: feat_plat_saf_dfa__ + mandatory_options: + id: ^feat_plat_saf_dfa__[0-9a-z_]+$ + violation_id: ^.*$ + violation_cause: ^.*$ + sufficient: ^(yes|no)$ + status: ^(valid|invalid)$ + mandatory_links: + mitigates: ^(feat_req__.*|aou_req__.*)$ + verifies: ^feat_arc_dyn__[0-9a-z_]*$ + optional_links: + mitigation_issue: ^https://github.com/.*$ + + feat_saf_dfa: + title: DFA + prefix: feat_saf_dfa__ + mandatory_options: + id: ^feat_saf_dfa__[0-9a-z_]+$ + violation_id: ^.*$ + violation_cause: ^.*$ + sufficient: ^(yes|no)$ + status: ^(valid|invalid)$ + mandatory_links: + mitigates: ^(feat_req__.*|aou_req__.*)$ + verifies: ^feat_arc_dyn__[0-9a-z_]*$ + optional_links: + mitigation_issue: ^https://github.com/.*$ + + comp_saf_dfa: + title: DFA + prefix: comp_saf_dfa__ + mandatory_options: + id: ^comp_saf_dfa__[0-9a-z_]+$ + violation_id: ^.*$ + violation_cause: ^.*$ + sufficient: ^(yes|no)$ + status: ^(valid|invalid)$ + mandatory_links: + mitigates: ^(comp_req__.*|aou_req__.*)$ + verifies: ^comp_arc_dyn__[0-9a-z_]*$ + optional_links: + mitigation_issue: ^https://github.com/.*$ + + # # Safety Analysis FMEA + feat_saf_fmea: + title: FMEA + prefix: feat_saf_fmea__ + mandatory_options: + id: ^feat_saf_fmea__[0-9a-z_]+$ + violation_id: ^.*$ + violation_cause: ^.*$ + sufficient: ^(yes|no)$ + status: ^(valid|invalid)$ + mandatory_links: + mitigates: ^(feat_req__.*|aou_req__.*)$ + verifies: ^feat_arc_dyn__[0-9a-z_]*$ + optional_links: + mitigation_issue: ^https://github.com/.*$ + + comp_saf_fmea: + title: FMEA + prefix: comp_saf_fmea__ + mandatory_options: + id: ^comp_saf_fmea__[0-9a-z_]+$ + violation_id: ^.*$ + violation_cause: ^.*$ + sufficient: ^(yes|no)$ + status: ^(valid|invalid)$ + mandatory_links: + mitigates: ^(comp_req__.*|aou_req__.*)$ + verifies: ^comp_arc_dyn__[0-9a-z_]*$ + optional_links: + mitigation_issue: ^https://github.com/.*$ + # Extra link types, which shall be available and allow need types to be linked to each other. # We use a dedicated linked type for each type of a connection, for instance from # a specification to a requirement. This makes filtering and visualization of such connections @@ -576,6 +653,14 @@ needs_extra_links: included_by: incoming: includes outgoing: included by + + mitigates: + incoming: mitigated by + outgoing: mitigates + + verifies: + incoming: verified by + outgoing: verifies ############################################################## # Graph Checks # The graph checks focus on the relation of the needs and their attributes. @@ -594,36 +679,33 @@ needs_extra_links: ############################################################## # req- Id: gd_req__req__linkage_architecture # req- Id: gd_req__req__linkage_safety + +# Checks if the child requirement has the at least the same safety level as the parent requirement. It's allowed to "overfill" the safety level of the parent. +# ASIL decomposition is not foreseen in S-CORE. Therefore it's not allowed to have a child requirement with a lower safety level than the parent requirement as +# it is possible in an decomposition case. +# If need-req is `QM`, parent must be `QM`. graph_checks: - # req- Id: gd_req__req__linkage_safety - req_safety_linkage: + req_safety_linkage_qm: needs: include: comp_req, feat_req - condition: - and: - - safety != QM - - status == valid + condition: safety == QM check: - satisfies: - and: - - safety != QM - - status == valid - req_linkage: + satisfies: safety == QM + # If need-req is `ASIL_B`, parent must be `QM` or `ASIL_B`. + req_safety_linkage_asil_b: needs: include: comp_req, feat_req - condition: status == valid + condition: safety == ASIL_B check: - # req- Id: gd_req__req__linkage_architecture - satisfies: status == valid - arch_safety_linkage: + satisfies: safety != ASIL_D + # saf - ID gd_req__saf_linkage_safety + # It shall be checked that Safety Analysis (DFA and FMEA) can only be linked via mitigate against + # - Requirements with the same ASIL or + # - Requirements with a higher ASIL + # as the corresponding ASIL of the Feature or Component that is analyzed. + saf_linkage_safety: needs: - include: comp_req, feat_req - condition: - and: - - safety != QM - - status == valid + include: feat_saf_fmea, comp_saf_fmea, feat_plat_saf_dfa, feat_saf_dfa, comp_saf_dfa + condition: safety == ASIL_B check: - fulfils: - and: - - safety != QM - - status == valid + mitigates: safety != QM diff --git a/src/extensions/score_metamodel/tests/rst/graph/test_metamodel_graph.rst b/src/extensions/score_metamodel/tests/rst/graph/test_metamodel_graph.rst index 65271498..b193749e 100644 --- a/src/extensions/score_metamodel/tests/rst/graph/test_metamodel_graph.rst +++ b/src/extensions/score_metamodel/tests/rst/graph/test_metamodel_graph.rst @@ -11,53 +11,245 @@ # # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* + #CHECK: check_metamodel_graph -.. feat_req:: Parent requirement - :id: feat_req__parent__abcd + +.. Checks if the child requirement has the at least the same safety level as the parent requirement. It's allowed to "overfill" the safety level of the parent. +.. ASIL decomposition is not foreseen in S-CORE. Therefore it's not allowed to have a child requirement with a lower safety level than the parent requirement as +.. it is possible in an decomposition case. +.. feat_req:: Parent requirement QM + :id: feat_req__parent__QM + :safety: QM + :status: valid + +.. feat_req:: Parent requirement ASIL_B + :id: feat_req__parent__ASIL_B + :safety: ASIL_B + :status: valid + +.. feat_req:: Parent requirement ASIL_D + :id: feat_req__parent__ASIL_D + :safety: ASIL_D + :status: valid + + +.. Positive Test: Child requirement QM. Parent requirement has the correct related safety level. Parent requirement is `QM`. +#EXPECT-NOT: feat_req__child__1: parent need `feat_req__parent__QM` does not fulfill condition `safety == QM`. + +.. feat_req:: Child requirement 1 + :id: feat_req__child__1 :safety: QM + :satisfies: feat_req__parent__QM :status: valid -.. Parent requirement has not the correct safety level -#EXPECT: feat_req__child__abce: parent need `feat_req__parent__abcd` does not fulfill condition `{'and': ['safety != QM', 'status == valid']}`. +.. Positive Test: Child requirement ASIL B. Parent requirement has the correct related safety level. Parent requirement is `QM`. +#EXPECT-NOT: feat_req__child__2: parent need `feat_req__parent__ASIL_B` does not fulfill condition `safety == QM`. -.. feat_req:: Child requirement - :id: feat_req__child__abce +.. feat_req:: Child requirement 2 + :id: feat_req__child__2 :safety: ASIL_B + :satisfies: feat_req__parent__ASIL_B + :status: valid + +.. Positive Test: Child requirement ASIL D. Parent requirement has the correct related safety level. Parent requirement is `QM`. +#EXPECT-NOT: feat_req__child__3: parent need `feat_req__parent__ASIL_D` does not fulfill condition `safety == QM`. + +.. feat_req:: Child requirement 3 + :id: feat_req__child__3 + :safety: ASIL_D + :satisfies: feat_req__parent__ASIL_D + :status: valid + +.. Negative Test: Child requirement QM. Parent requirement is `ASIL_B`. Child cant fulfill the safety level of the parent. +#EXPECT: feat_req__child__4: parent need `feat_req__parent__ASIL_B` does not fulfill condition `safety == QM`. + +.. comp_req:: Child requirement 4 + :id: feat_req__child__4 + :safety: QM + :satisfies: feat_req__parent__ASIL_B :status: valid - :satisfies: feat_req__parent__abcd -.. feat_req:: Parent requirement 2 - :id: feat_req__parent2__abcd +.. Negative Test: Child requirement QM. Parent requirement is `ASIL_D`. Child cant fulfill the safety level of the parent. +#EXPECT: feat_req__child__5: parent need `feat_req__parent__ASIL_D` does not fulfill condition `safety == QM`. + +.. comp_req:: Child requirement 5 + :id: feat_req__child__5 + :safety: QM + :satisfies: feat_req__parent__ASIL_D + :status: valid + +.. Positive Test: Child requirement ASIL_B. Parent requirement has the correct related safety level. Parent requirement is `QM`. +#EXPECT-NOT: feat_req__child__6: parent need `feat_req__parent__QM` does not fulfill condition `safety != ASIL_D`. + +.. feat_req:: Child requirement 6 + :id: feat_req__child__6 :safety: ASIL_B + :satisfies: feat_req__parent__QM :status: valid -.. Parent requirement has the correct safety level -#EXPECT-NOT: feat_req__child2__abce: parent need `feat_req__parent2__abcd` does not fulfill condition +.. Positive Test: Child requirement ASIL_B. Parent requirement has the correct related safety level. Parent requirement is `ASIL_B`. +#EXPECT-NOT: feat_req__child__7: parent need `feat_req__parent__ASIL_B` does not fulfill condition `safety != ASIL_D`. -.. feat_req:: Child requirement 2 - :id: feat_req__child2__abce +.. feat_req:: Child requirement 7 + :id: feat_req__child__7 + :safety: ASIL_B + :satisfies: feat_req__parent__ASIL_B + :status: valid + +.. Negative Test: Child requirement ASIL_B. Parent requirement is `ASIL_D`. Child cant fulfill the safety level of the parent. +#EXPECT: feat_req__child__8: parent need `feat_req__parent__ASIL_D` does not fulfill condition `safety != ASIL_D`. + +.. comp_req:: Child requirement 8 + :id: feat_req__child__8 :safety: ASIL_B + :satisfies: feat_req__parent__ASIL_D :status: valid - :satisfies: feat_req__parent__abcd + + .. Parent requirement does not exist -#EXPECT: feat_req__child3__abce: Parent need `feat_req__parent0__abcd` not found in needs_dict. +#EXPECT: feat_req__child__9: Parent need `feat_req__parent0__abcd` not found in needs_dict. -.. feat_req:: Child requirement 3 - :id: feat_req__child3__abce +.. feat_req:: Child requirement 9 + :id: feat_req__child__9 :safety: ASIL_B :status: valid :satisfies: feat_req__parent0__abcd -.. feat_req:: Parent requirement 3 - :id: feat_req__parent3__abcd - :status: invalid -.. Graph check without combined condition (no and or or) -#EXPECT: comp_req__parent4__abcd: parent need `feat_req__parent3__abcd` does not fulfill condition `status == valid`. +.. Mitigation of Safety Analysis (FMEA and DFA) shall be checked. Mitigation shall have the same or higher safety level than the analysed item. +.. Negative Test: Linked to a mitigation that is lower than the safety level of the analysed item. +#EXPECT: feat_saf_dfa__child__10: parent need `feat_req__parent__QM` does not fulfill condition `safety != QM`. -.. comp_req:: Child requirement 4 - :id: comp_req__parent4__abcd +.. feat_saf_dfa:: Child requirement 10 + :id: feat_saf_dfa__child__10 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__QM + +.. Positive Test: Linked to a mitigation that is equal to the safety level of the analysed item. +#EXPECT-NOT: feat_saf_dfa__child__11: parent need `feat_req__parent__ASIL_B` does not fulfill condition `safety != QM`. + +.. feat_saf_dfa:: Child requirement 11 + :id: feat_saf_dfa__child__11 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__ASIL_B + +.. Positive Test: Linked to a mitigation that is higher to the safety level of the analysed item. +#EXPECT-NOT: feat_saf_dfa__child__12: parent need `feat_req__parent__ASIL_D` does not fulfill condition `safety != QM`. + +.. feat_saf_dfa:: Child requirement 12 + :id: feat_saf_dfa__child__12 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__ASIL_D + +.. Negative Test: Linked to a mitigation that is lower than the safety level of the analysed item. +#EXPECT: comp_saf_dfa__child__13: parent need `feat_req__parent__QM` does not fulfill condition `safety != QM`. + +.. comp_saf_dfa:: Child requirement 13 + :id: comp_saf_dfa__child__13 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__QM + +.. Positive Test: Linked to a mitigation that is equal to the safety level of the analysed item. +#EXPECT-NOT: comp_saf_dfa__child__14: parent need `feat_req__parent__ASIL_B` does not fulfill condition `safety != QM`. + +.. comp_saf_dfa:: Child requirement 14 + :id: comp_saf_dfa__child__14 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__ASIL_B + +.. Positive Test: Linked to a mitigation that is higher to the safety level of the analysed item. +#EXPECT-NOT: comp_saf_dfa__child__15: parent need `feat_req__parent__ASIL_D` does not fulfill condition `safety != QM`. + +.. comp_saf_dfa:: Child requirement 15 + :id: comp_saf_dfa__child__15 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__ASIL_D + +.. Negative Test: Linked to a mitigation that is lower than the safety level of the analysed item. +#EXPECT: feat_plat_saf_dfa__child__16: parent need `feat_req__parent__QM` does not fulfill condition `safety != QM`. + +.. feat_plat_saf_dfa:: Child requirement 16 + :id: feat_plat_saf_dfa__child__16 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__QM + +.. Positive Test: Linked to a mitigation that is equal to the safety level of the analysed item. +#EXPECT-NOT: feat_plat_saf_dfa__child__17: parent need `feat_req__parent__ASIL_B` does not fulfill condition `safety != QM`. + +.. feat_plat_saf_dfa:: Child requirement 17 + :id: feat_plat_saf_dfa__child__17 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__ASIL_B + +.. Positive Test: Linked to a mitigation that is higher to the safety level of the analysed item. +#EXPECT-NOT: feat_plat_saf_dfa__child__18: parent need `feat_req__parent__ASIL_D` does not fulfill condition `safety != QM`. + +.. feat_plat_saf_dfa:: Child requirement 18 + :id: feat_plat_saf_dfa__child__15 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__ASIL_D + +.. Negative Test: Linked to a mitigation that is lower than the safety level of the analysed item. +#EXPECT: feat_saf_fmea__child__19: parent need `feat_req__parent__QM` does not fulfill condition `safety != QM`. + +.. feat_saf_fmea:: Child requirement 19 + :id: feat_saf_fmea__child__19 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__QM + +.. Positive Test: Linked to a mitigation that is equal to the safety level of the analysed item. +#EXPECT-NOT: feat_saf_fmea__child__20: parent need `feat_req__parent__ASIL_B` does not fulfill condition `safety != QM`. + +.. feat_saf_fmea:: Child requirement 20 + :id: feat_saf_fmea__child__20 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__ASIL_B + +.. Positive Test: Linked to a mitigation that is higher to the safety level of the analysed item. +#EXPECT-NOT: feat_saf_fmea__child__21: parent need `feat_req__parent__ASIL_D` does not fulfill condition `safety != QM`. + +.. feat_saf_fmea:: Child requirement 21 + :id: feat_saf_fmea__child__21 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__ASIL_D + +.. Negative Test: Linked to a mitigation that is lower than the safety level of the analysed item. +#EXPECT: comp_saf_fmea__child__22: parent need `feat_req__parent__QM` does not fulfill condition `safety != QM`. + +.. comp_saf_fmea:: Child requirement 22 + :id: comp_saf_fmea__child__22 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__QM + +.. Positive Test: Linked to a mitigation that is equal to the safety level of the analysed item. +#EXPECT-NOT: comp_saf_fmea__child__23: parent need `feat_req__parent__ASIL_B` does not fulfill condition `safety != QM`. + +.. comp_saf_fmea:: Child requirement 23 + :id: comp_saf_fmea__child__23 + :safety: ASIL_B + :status: valid + :mitigates: feat_req__parent__ASIL_B + +.. Positive Test: Linked to a mitigation that is higher to the safety level of the analysed item. +#EXPECT-NOT: comp_saf_fmea__child__24: parent need `feat_req__parent__ASIL_D` does not fulfill condition `safety != QM`. + +.. comp_saf_fmea:: Child requirement 24 + :id: comp_saf_fmea__child__24 + :safety: ASIL_B :status: valid - :satisfies: feat_req__parent3__abcd + :mitigates: feat_req__parent__ASIL_D diff --git a/src/extensions/score_metamodel/tests/rst/options/test_options_extra_option.rst b/src/extensions/score_metamodel/tests/rst/options/test_options_extra_option.rst index a363f8ac..fd7de88e 100644 --- a/src/extensions/score_metamodel/tests/rst/options/test_options_extra_option.rst +++ b/src/extensions/score_metamodel/tests/rst/options/test_options_extra_option.rst @@ -25,3 +25,5 @@ .. std_wp:: This is a test :id: std_wp__test__abce + + diff --git a/src/extensions/score_metamodel/tests/rst/options/test_options_options.rst b/src/extensions/score_metamodel/tests/rst/options/test_options_options.rst index c829fe92..016f27f1 100644 --- a/src/extensions/score_metamodel/tests/rst/options/test_options_options.rst +++ b/src/extensions/score_metamodel/tests/rst/options/test_options_options.rst @@ -13,19 +13,22 @@ # ******************************************************************************* #CHECK: check_options + .. Required option: `status` is missing #EXPECT: std_wp__test__abcd: is missing required option: `status`. .. std_wp:: This is a test :id: std_wp__test__abcd + .. All required options are present -#EXPECT-NOT: is missing required option +#EXPECT-NOT: std_wp__test__abcd: is missing required option .. std_wp:: This is a test :id: std_wp__test__abce :status: active + .. Required link `satisfies` refers to wrong requirement type #EXPECT: feat_req__abce.satisfies (['std_wp__test__abce']): does not follow pattern `^stkh_req__.*$`. @@ -58,6 +61,7 @@ .. feat_req:: Child requirement :id: feat_req__abcf + .. All required links are present #EXPECT-NOT: feat_req__abcg: is missing required link @@ -67,3 +71,489 @@ .. stkh_req:: Parent requirement :id: stkh_req__abcd + + +.. Test if the `sufficient` option for Safety Analysis (FMEA and DFA) follows the pattern `^(yes|no)$` +#EXPECT: feat_saf_fmea__test__bad_1.sufficient (QM): does not follow pattern `^(yes|no)$`. + +.. feat_saf_fmea:: This is a test + :id: feat_saf_fmea__test__bad_1 + :sufficient: QM + +#EXPECT-NOT: feat_saf_fmea__test__good_2.sufficient (yes): does not follow pattern `^(yes|no)$`. + +.. feat_saf_fmea:: This is a test + :id: feat_saf_fmea__test__2 + :sufficient: yes + +#EXPECT-NOT: feat_saf_fmea__test__good_3.sufficient (no): does not follow pattern `^(yes|no)$`. + +.. feat_saf_fmea:: This is a test + :id: feat_saf_fmea__test__3 + :sufficient: no + +#EXPECT: comp_saf_fmea__test__bad_4.sufficient (QM): does not follow pattern `^(yes|no)$`. + +.. comp_saf_fmea:: This is a test + :id: comp_saf_fmea__test__bad_4 + :sufficient: QM + +#EXPECT-NOT: comp_saf_fmea__test__good_5.sufficient (yes): does not follow pattern `^(yes|no)$`. + +.. comp_saf_fmea:: This is a test + :id: comp_saf_fmea__test__5 + :sufficient: yes + +#EXPECT-NOT: comp_saf_fmea__test__good_6.sufficient (no): does not follow pattern `^(yes|no)$`. + +.. comp_saf_fmea:: This is a test + :id: comp_saf_fmea__test__6 + :sufficient: no + +#EXPECT: feat_plat_saf_dfa__test__bad_7.sufficient (QM): does not follow pattern `^(yes|no)$`. + +.. feat_plat_saf_dfa:: This is a test + :id: feat_plat_saf_dfa__test__bad_7 + :sufficient: QM + +#EXPECT-NOT: feat_plat_saf_dfa__test__good_8.sufficient (yes): does not follow pattern `^(yes|no)$`. + +.. feat_plat_saf_dfa:: This is a test + :id: feat_plat_saf_dfa__test__8 + :sufficient: yes + +#EXPECT-NOT: feat_plat_saf_dfa__test__good_9.sufficient (no): does not follow pattern `^(yes|no)$`. + +.. feat_plat_saf_dfa:: This is a test + :id: feat_plat_saf_dfa__test__9 + :sufficient: no + +#EXPECT: feat_saf_dfa__test__bad_10.sufficient (QM): does not follow pattern `^(yes|no)$`. + +.. feat_saf_dfa:: This is a test + :id: feat_saf_dfa__test__bad_10 + :sufficient: QM + +#EXPECT-NOT: feat_saf_dfa__test__good_11.sufficient (yes): does not follow pattern `^(yes|no)$`. + +.. feat_saf_dfa:: This is a test + :id: feat_saf_dfa__test__11 + :sufficient: yes + +#EXPECT-NOT: feat_saf_dfa__test__good_12.sufficient (no): does not follow pattern `^(yes|no)$`. + +.. feat_saf_dfa:: This is a test + :id: feat_saf_dfa__test__12 + :sufficient: no + +#EXPECT: comp_saf_dfa__test__bad_13.sufficient (QM): does not follow pattern `^(yes|no)$`. + +.. comp_saf_dfa:: This is a test + :id: comp_saf_dfa__test__bad_13 + :sufficient: QM + +#EXPECT-NOT: comp_saf_dfa__test__good_14.sufficient (yes): does not follow pattern `^(yes|no)$`. + +.. comp_saf_dfa:: This is a test + :id: comp_saf_dfa__test__14 + :sufficient: yes + +#EXPECT-NOT: comp_saf_dfa__test__good_15.sufficient (no): does not follow pattern `^(yes|no)$`. + +.. comp_saf_dfa:: This is a test + :id: comp_saf_dfa__test__15 + :sufficient: no + + +.. Test that the `sufficient` option is case sensitive and does not accept values other than `yes` or `no` +#EXPECT: feat_saf_fmea__test__bad_16.sufficient (yEs): does not follow pattern `^(yes|no)$`. + +.. feat_saf_fmea:: This is a test + :id: feat_saf_fmea__test__bad_16 + :sufficient: yEs + + + +.. comp_req:: Child requirement ASIL_B + :id: comp_req__child__ASIL_B + :safety: ASIL_B + :status: valid + + +.. Negative Test: Linked to a non-allowed requirement type. +#EXPECT: feat_saf_fmea__child__25.mitigates (['comp_req__child__ASIL_B']): does not follow pattern `^(feat_req__.*|aou_req__.*)$`. + +.. feat_saf_fmea:: Child requirement 25 + :id: feat_saf_fmea__child__25 + :safety: ASIL_B + :status: valid + :mitigates: comp_req__child__ASIL_B + + +.. Negative Test: Linked to a non-allowed requirement type. +#EXPECT: feat_saf_fmea__child__26.verifies (['comp_req__child__ASIL_B']): does not follow pattern `^feat_arc_dyn__[0-9a-z_]*$`. + +.. feat_saf_fmea:: Child requirement 26 + :id: feat_saf_fmea__child__26 + :safety: ASIL_B + :status: valid + :verifies: comp_req__child__ASIL_B + + +.. Tests if the attribute `safety` follows the pattern `^(QM|ASIL_B)$` +#EXPECT-NOT: doc__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. document:: This is a test document + :id: doc__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: doc__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. document:: This is a test document + :id: doc__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: doc__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. document:: This is a test document +.. :id: doc__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: stkh_req__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. stkh_req:: This is a test + :id: stkh_req__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: stkh_req__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. stkh_req:: This is a test + :id: stkh_req__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: stkh_req__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. stkh_req:: This is a test +.. :id: stkh_req__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: feat_req__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. feat_req:: This is a test + :id: feat_req__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: feat_req__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. feat_req:: This is a test + :id: feat_req__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: feat_req__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. feat_req:: This is a test +.. :id: feat_req__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: comp_req__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. comp_req:: This is a test + :id: comp_req__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: comp_req__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. comp_req:: This is a test + :id: comp_req__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: comp_req__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. comp_req:: This is a test +.. :id: comp_req__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: tool_req__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. tool_req:: This is a test + :id: tool_req__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: tool_req__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. tool_req:: This is a test + :id: tool_req__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: tool_req__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. tool_req:: This is a test +.. :id: tool_req__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: aou_req__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. aou_req:: This is a test + :id: aou_req__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: aou_req__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. aou_req:: This is a test + :id: aou_req__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: aou_req__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. aou_req:: This is a test +.. :id: aou_req__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: feat_arc_sta__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. feat_arc_sta:: This is a test + :id: feat_arc_sta__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: feat_arc_sta__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. feat_arc_sta:: This is a test + :id: feat_arc_sta__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: feat_arc_sta__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. feat_arc_sta:: This is a test +.. :id: feat_arc_sta__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: feat_arc_dyn__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. feat_arc_dyn:: This is a test + :id: feat_arc_dyn__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: feat_arc_dyn__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. feat_arc_dyn:: This is a test + :id: feat_arc_dyn__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: feat_arc_dyn__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. feat_arc_dyn:: This is a test +.. :id: feat_arc_dyn__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: logic_arc_int__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. logic_arc_int:: This is a test + :id: logic_arc_int__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: logic_arc_int__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. logic_arc_int:: This is a test + :id: logic_arc_int__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: logic_arc_int__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. logic_arc_int:: This is a test +.. :id: logic_arc_int__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: logic_arc_int_op__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. logic_arc_int_op:: This is a test + :id: logic_arc_int_op__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: logic_arc_int_op__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. logic_arc_int_op:: This is a test + :id: logic_arc_int_op__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: logic_arc_int_op__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. logic_arc_int_op:: This is a test +.. :id: logic_arc_int_op__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: comp_arc_sta__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. comp_arc_sta:: This is a test + :id: comp_arc_sta__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: comp_arc_sta__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. comp_arc_sta:: This is a test + :id: comp_arc_sta__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: comp_arc_sta__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. comp_arc_sta:: This is a test +.. :id: comp_arc_sta__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: comp_arc_dyn__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. comp_arc_dyn:: This is a test + :id: comp_arc_dyn__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: comp_arc_dyn__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. comp_arc_dyn:: This is a test + :id: comp_arc_dyn__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: comp_arc_dyn__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. comp_arc_dyn:: This is a test +.. :id: comp_arc_dyn__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: real_arc_int__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. real_arc_int:: This is a test + :id: real_arc_int__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: real_arc_int__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. real_arc_int:: This is a test + :id: real_arc_int__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: real_arc_int__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. real_arc_int:: This is a test +.. :id: real_arc_int__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: real_arc_int_op__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. real_arc_int_op:: This is a test + :id: real_arc_int_op__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: real_arc_int_op__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. real_arc_int_op:: This is a test + :id: real_arc_int_op__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: real_arc_int_op__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. real_arc_int_op:: This is a test +.. :id: real_arc_int_op__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: dd_sta__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. dd_sta:: This is a test + :id: dd_sta__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: dd_sta__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. dd_sta:: This is a test + :id: dd_sta__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: dd_sta__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. dd_sta:: This is a test +.. :id: dd_sta__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: dd_dyn__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. dd_dyn:: This is a test + :id: dd_dyn__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: dd_dyn__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. dd_dyn:: This is a test + :id: dd_dyn__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: dd_dyn__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. dd_dyn:: This is a test +.. :id: dd_dyn__test_bad_1 +.. :status: valid +.. :safety: ASIL_D + +#EXPECT-NOT: sw_unit__test_good_1.safety (QM): does not follow pattern `^(QM|ASIL_B)$`. + +.. sw_unit:: This is a test + :id: sw_unit__test_good_1 + :status: valid + :safety: QM + +#EXPECT-NOT: sw_unit__test_good_2.safety (ASIL_B): does not follow pattern `^(QM|ASIL_B)$`. + +.. sw_unit:: This is a test + :id: sw_unit__test_good_2 + :status: valid + :safety: ASIL_B + +.. #EXPECT: sw_unit__test_bad_1.safety (ASIL_D): does not follow pattern `^(QM|ASIL_B)$`. + +.. .. sw_unit:: This is a test +.. :id: sw_unit__test_bad_1 +.. :status: valid +.. :safety: ASIL_D diff --git a/src/extensions/score_metamodel/tests/test_rules_file_based.py b/src/extensions/score_metamodel/tests/test_rules_file_based.py index 24aa324e..f0268ec2 100644 --- a/src/extensions/score_metamodel/tests/test_rules_file_based.py +++ b/src/extensions/score_metamodel/tests/test_rules_file_based.py @@ -185,7 +185,7 @@ def test_rst_files( # Collect the warnings warnings = app.warning.getvalue().splitlines() - # print(f"Warnings: {warnings}") + print(f"Warnings: {warnings}") # Check if the expected warnings are present for warning_info in rst_data.warning_infos: