From 6b8471beefebb6f0c286e8f07589bed639bc9897 Mon Sep 17 00:00:00 2001 From: romanodanilo Date: Tue, 2 Jul 2024 14:19:16 +0200 Subject: [PATCH] Add main and constant check and tests Signed-off-by: romanodanilo --- qc_otx/checks/core_checker/__init__.py | 2 + qc_otx/checks/core_checker/core_checker.py | 4 + .../mandatory_constant_initialization.py | 64 +++++ .../core_checker/public_main_procedure.py | 66 +++++ .../data/Core_Chk008/Core_Chk008_negative.otx | 33 +++ .../Core_Chk008_negative_no_visibility.otx | 33 +++ .../Core_Chk008_negative_two_mains.otx | 27 ++ .../data/Core_Chk008/Core_Chk008_positive.otx | 32 +++ .../Core_Chk008_positive_no_main.otx | 26 ++ .../Core_Chk008_positive_two_mains.otx | 27 ++ .../data/Core_Chk009/Core_Chk009_negative.otx | 21 ++ .../Core_Chk009_negative_multiple.otx | 25 ++ .../Core_Chk009_negative_multiple_errors.otx | 25 ++ .../data/Core_Chk009/Core_Chk009_positive.otx | 21 ++ .../Core_Chk009_positive_multiple.otx | 29 +++ tests/test_core_checks.py | 244 ++++++++++++++++++ 16 files changed, 679 insertions(+) create mode 100644 qc_otx/checks/core_checker/mandatory_constant_initialization.py create mode 100644 qc_otx/checks/core_checker/public_main_procedure.py create mode 100644 tests/data/Core_Chk008/Core_Chk008_negative.otx create mode 100644 tests/data/Core_Chk008/Core_Chk008_negative_no_visibility.otx create mode 100644 tests/data/Core_Chk008/Core_Chk008_negative_two_mains.otx create mode 100644 tests/data/Core_Chk008/Core_Chk008_positive.otx create mode 100644 tests/data/Core_Chk008/Core_Chk008_positive_no_main.otx create mode 100644 tests/data/Core_Chk008/Core_Chk008_positive_two_mains.otx create mode 100644 tests/data/Core_Chk009/Core_Chk009_negative.otx create mode 100644 tests/data/Core_Chk009/Core_Chk009_negative_multiple.otx create mode 100644 tests/data/Core_Chk009/Core_Chk009_negative_multiple_errors.otx create mode 100644 tests/data/Core_Chk009/Core_Chk009_positive.otx create mode 100644 tests/data/Core_Chk009/Core_Chk009_positive_multiple.otx diff --git a/qc_otx/checks/core_checker/__init__.py b/qc_otx/checks/core_checker/__init__.py index 3bd1a66..ffe4813 100644 --- a/qc_otx/checks/core_checker/__init__.py +++ b/qc_otx/checks/core_checker/__init__.py @@ -7,3 +7,5 @@ from . import ( have_specification_if_no_realisation_exists as have_specification_if_no_realisation_exists, ) +from . import public_main_procedure as public_main_procedure +from . import mandatory_constant_initialization as mandatory_constant_initialization diff --git a/qc_otx/checks/core_checker/core_checker.py b/qc_otx/checks/core_checker/core_checker.py index d61ab9a..be1684c 100644 --- a/qc_otx/checks/core_checker/core_checker.py +++ b/qc_otx/checks/core_checker/core_checker.py @@ -14,6 +14,8 @@ no_dead_import_links, no_unused_imports, have_specification_if_no_realisation_exists, + public_main_procedure, + mandatory_constant_initialization, ) @@ -33,6 +35,8 @@ def run_checks(checker_data: models.CheckerData) -> None: no_dead_import_links.check_rule, # Chk003 no_unused_imports.check_rule, # Chk004 have_specification_if_no_realisation_exists.check_rule, # Chk007 + public_main_procedure.check_rule, # Chk008 + mandatory_constant_initialization.check_rule, # Chk009 ] for rule in rule_list: diff --git a/qc_otx/checks/core_checker/mandatory_constant_initialization.py b/qc_otx/checks/core_checker/mandatory_constant_initialization.py new file mode 100644 index 0000000..d85f918 --- /dev/null +++ b/qc_otx/checks/core_checker/mandatory_constant_initialization.py @@ -0,0 +1,64 @@ +import logging, os + +from typing import List + +from lxml import etree + +from qc_baselib import Result, IssueSeverity + +from qc_otx import constants +from qc_otx.checks import models + +from qc_otx.checks.core_checker import core_constants + + +def check_rule(checker_data: models.CheckerData) -> None: + """ + Implements core checker rule Core_Chk009 + Criterion: Constant declarations shall always be initialized. + Severity: Critical + """ + logging.info("Executing mandatory_constant_initialization check") + + issue_severity = IssueSeverity.ERROR + + rule_uid = checker_data.result.register_rule( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=core_constants.CHECKER_ID, + emanating_entity="asam.net", + standard="otx", + definition_setting="1.0.0", + rule_full_name="core.chk_009.mandatory_constant_initialization", + ) + + tree = checker_data.input_file_xml_root + root = tree.getroot() + # Use XPath to find all nodes constant + constant_nodes = tree.xpath("//constant") + + for constant_node in constant_nodes: + constant_name = constant_node.get("name") + + # Define the XPath expression for the sequence of children + xpath_expr = ".//realisation/dataType/init" + + # Use XPath to find if the sequence exists + is_valid = constant_node.xpath(xpath_expr) + + if not is_valid: + current_xpath = tree.getpath(constant_node) + issue_id = checker_data.result.register_issue( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=core_constants.CHECKER_ID, + description="Issue flagging when a constant is not initialized", + level=issue_severity, + rule_uid=rule_uid, + ) + + checker_data.result.add_xml_location( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=core_constants.CHECKER_ID, + issue_id=issue_id, + xpath=current_xpath, + description=f"Constant {constant_name} at {current_xpath} is not initialized", + ) diff --git a/qc_otx/checks/core_checker/public_main_procedure.py b/qc_otx/checks/core_checker/public_main_procedure.py new file mode 100644 index 0000000..574f444 --- /dev/null +++ b/qc_otx/checks/core_checker/public_main_procedure.py @@ -0,0 +1,66 @@ +import logging, os + +from typing import List + +from lxml import etree + +from qc_baselib import Result, IssueSeverity + +from qc_otx import constants +from qc_otx.checks import models + +from qc_otx.checks.core_checker import core_constants + + +def check_rule(checker_data: models.CheckerData) -> None: + """ + Implements core checker rule Core_Chk008 + Criterion: The value of attribute visibility shall always be "PUBLIC" if the procedure name is "main". + ​Severity: Critical + """ + logging.info("Executing public_main_procedure check") + + issue_severity = IssueSeverity.ERROR + + rule_uid = checker_data.result.register_rule( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=core_constants.CHECKER_ID, + emanating_entity="asam.net", + standard="otx", + definition_setting="1.0.0", + rule_full_name="core.chk_008.public_main_procedure", + ) + + tree = checker_data.input_file_xml_root + root = tree.getroot() + + # Use XPath to find all nodes procedures + procedure_nodes = tree.xpath(f"//procedure") + + for procedure_node in procedure_nodes: + procedure_name = procedure_node.get("name") + procedure_visibility = procedure_node.get("visibility") + + # Visibility defaults to private if not specified + if procedure_visibility is None: + procedure_visibility = "PRIVATE" + + has_issue = procedure_name == "main" and procedure_visibility != "PUBLIC" + + if has_issue: + current_xpath = tree.getpath(procedure_node) + issue_id = checker_data.result.register_issue( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=core_constants.CHECKER_ID, + description="Issue flagging when procedure called main has not PUBLIC visibility", + level=issue_severity, + rule_uid=rule_uid, + ) + + checker_data.result.add_xml_location( + checker_bundle_name=constants.BUNDLE_NAME, + checker_id=core_constants.CHECKER_ID, + issue_id=issue_id, + xpath=current_xpath, + description=f"Procedure at {current_xpath} is called main but its visibility is not PUBLIC", + ) diff --git a/tests/data/Core_Chk008/Core_Chk008_negative.otx b/tests/data/Core_Chk008/Core_Chk008_negative.otx new file mode 100644 index 0000000..f6d8f3b --- /dev/null +++ b/tests/data/Core_Chk008/Core_Chk008_negative.otx @@ -0,0 +1,33 @@ + + + + + + + + + + + + This is an empty top-level procedure, a test sequence + + + + + + An empty procedure implementing a signature, with validity information. + + + + + + + + diff --git a/tests/data/Core_Chk008/Core_Chk008_negative_no_visibility.otx b/tests/data/Core_Chk008/Core_Chk008_negative_no_visibility.otx new file mode 100644 index 0000000..0499f82 --- /dev/null +++ b/tests/data/Core_Chk008/Core_Chk008_negative_no_visibility.otx @@ -0,0 +1,33 @@ + + + + + + + + + + + + This is an empty top-level procedure, a test sequence + + + + + + An empty procedure implementing a signature, with validity information. + + + + + + + + diff --git a/tests/data/Core_Chk008/Core_Chk008_negative_two_mains.otx b/tests/data/Core_Chk008/Core_Chk008_negative_two_mains.otx new file mode 100644 index 0000000..dbc577e --- /dev/null +++ b/tests/data/Core_Chk008/Core_Chk008_negative_two_mains.otx @@ -0,0 +1,27 @@ + + + + + + This is an empty top-level procedure, a test sequence + + + + + + + This is a second empty top-level procedure, a test sequence + + + + + + + + diff --git a/tests/data/Core_Chk008/Core_Chk008_positive.otx b/tests/data/Core_Chk008/Core_Chk008_positive.otx new file mode 100644 index 0000000..8be2a06 --- /dev/null +++ b/tests/data/Core_Chk008/Core_Chk008_positive.otx @@ -0,0 +1,32 @@ + + + + + + + + + + + This is an empty top-level procedure, a test sequence + + + + + + An empty procedure implementing a signature, with validity information. + + + + + + + + diff --git a/tests/data/Core_Chk008/Core_Chk008_positive_no_main.otx b/tests/data/Core_Chk008/Core_Chk008_positive_no_main.otx new file mode 100644 index 0000000..e71e92c --- /dev/null +++ b/tests/data/Core_Chk008/Core_Chk008_positive_no_main.otx @@ -0,0 +1,26 @@ + + + + + + + + + + + An empty procedure implementing a signature, with validity information. + + + + + + + + diff --git a/tests/data/Core_Chk008/Core_Chk008_positive_two_mains.otx b/tests/data/Core_Chk008/Core_Chk008_positive_two_mains.otx new file mode 100644 index 0000000..948a248 --- /dev/null +++ b/tests/data/Core_Chk008/Core_Chk008_positive_two_mains.otx @@ -0,0 +1,27 @@ + + + + + + + This is an empty top-level procedure, a test sequence + + + + + + This is a second empty top-level procedure, a test sequence + + + + + + + + diff --git a/tests/data/Core_Chk009/Core_Chk009_negative.otx b/tests/data/Core_Chk009/Core_Chk009_negative.otx new file mode 100644 index 0000000..df68069 --- /dev/null +++ b/tests/data/Core_Chk009/Core_Chk009_negative.otx @@ -0,0 +1,21 @@ + + + + + + + This defines global constant + + + + + + + + diff --git a/tests/data/Core_Chk009/Core_Chk009_negative_multiple.otx b/tests/data/Core_Chk009/Core_Chk009_negative_multiple.otx new file mode 100644 index 0000000..82112ba --- /dev/null +++ b/tests/data/Core_Chk009/Core_Chk009_negative_multiple.otx @@ -0,0 +1,25 @@ + + + + + + This defines global constant + + + + + + + + + This defines another global constant + + + + diff --git a/tests/data/Core_Chk009/Core_Chk009_negative_multiple_errors.otx b/tests/data/Core_Chk009/Core_Chk009_negative_multiple_errors.otx new file mode 100644 index 0000000..aa1228b --- /dev/null +++ b/tests/data/Core_Chk009/Core_Chk009_negative_multiple_errors.otx @@ -0,0 +1,25 @@ + + + + + + + This defines global constant + + + + + + + + This defines another global constant + + + + diff --git a/tests/data/Core_Chk009/Core_Chk009_positive.otx b/tests/data/Core_Chk009/Core_Chk009_positive.otx new file mode 100644 index 0000000..8e193b3 --- /dev/null +++ b/tests/data/Core_Chk009/Core_Chk009_positive.otx @@ -0,0 +1,21 @@ + + + + + + This defines global constant + + + + + + + + + diff --git a/tests/data/Core_Chk009/Core_Chk009_positive_multiple.otx b/tests/data/Core_Chk009/Core_Chk009_positive_multiple.otx new file mode 100644 index 0000000..b3a6bd2 --- /dev/null +++ b/tests/data/Core_Chk009/Core_Chk009_positive_multiple.otx @@ -0,0 +1,29 @@ + + + + + + This defines global constant + + + + + + + + This defines another global constant + + + + + + + + + diff --git a/tests/test_core_checks.py b/tests/test_core_checks.py index 66be1b3..2240773 100644 --- a/tests/test_core_checks.py +++ b/tests/test_core_checks.py @@ -317,3 +317,247 @@ def test_chk007_negative_empty_string( assert core_issues[0].level == IssueSeverity.WARNING test_utils.cleanup_files() + + +def test_chk008_positive( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk008" + target_file_name = f"Core_Chk008_positive.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" + ) + assert len(core_issues) == 0 + test_utils.cleanup_files() + + +def test_chk008_positive_two_mains( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk008" + target_file_name = f"Core_Chk008_positive_two_mains.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" + ) + assert len(core_issues) == 0 + test_utils.cleanup_files() + + +def test_chk008_positive_no_main( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk008" + target_file_name = f"Core_Chk008_positive_no_main.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" + ) + assert len(core_issues) == 0 + test_utils.cleanup_files() + + +def test_chk008_negative( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk008" + target_file_name = f"Core_Chk008_negative.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" + ) + assert len(core_issues) == 1 + assert core_issues[0].level == IssueSeverity.ERROR + + test_utils.cleanup_files() + + +def test_chk008_negative_two_mains( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk008" + target_file_name = f"Core_Chk008_negative_two_mains.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" + ) + assert len(core_issues) == 1 + assert core_issues[0].level == IssueSeverity.ERROR + + test_utils.cleanup_files() + + +def test_chk008_negative_no_visibility( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk008" + target_file_name = f"Core_Chk008_negative_no_visibility.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_008.public_main_procedure" + ) + assert len(core_issues) == 1 + assert core_issues[0].level == IssueSeverity.ERROR + + test_utils.cleanup_files() + + +def test_chk009_positive( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk009" + target_file_name = f"Core_Chk009_positive.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" + ) + assert len(core_issues) == 0 + test_utils.cleanup_files() + + +def test_chk009_positive_multiple( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk009" + target_file_name = f"Core_Chk009_positive_multiple.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" + ) + assert len(core_issues) == 0 + test_utils.cleanup_files() + + +def test_chk009_negative( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk009" + target_file_name = f"Core_Chk009_negative.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" + ) + assert len(core_issues) == 1 + assert core_issues[0].level == IssueSeverity.ERROR + + test_utils.cleanup_files() + + +def test_chk009_negative_multiple( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk009" + target_file_name = f"Core_Chk009_negative_multiple.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" + ) + assert len(core_issues) == 1 + assert core_issues[0].level == IssueSeverity.ERROR + + test_utils.cleanup_files() + + +def test_chk009_negative_multiple_errors( + monkeypatch, +) -> None: + base_path = "tests/data/Core_Chk009" + target_file_name = f"Core_Chk009_negative_multiple_errors.otx" + target_file_path = os.path.join(base_path, target_file_name) + + test_utils.create_test_config(target_file_path) + + test_utils.launch_main(monkeypatch) + + result = Result() + result.load_from_file(test_utils.REPORT_FILE_PATH) + + core_issues = result.get_issues_by_rule_uid( + "asam.net:otx:1.0.0:core.chk_009.mandatory_constant_initialization" + ) + assert len(core_issues) == 2 + assert core_issues[0].level == IssueSeverity.ERROR + assert core_issues[1].level == IssueSeverity.ERROR + + test_utils.cleanup_files()