Skip to content

Commit

Permalink
Add valid parameter check declaration
Browse files Browse the repository at this point in the history
Signed-off-by: romanodanilo <[email protected]>
  • Loading branch information
romanodanilo committed Jul 9, 2024
1 parent 8042f96 commit 63790e5
Show file tree
Hide file tree
Showing 9 changed files with 353 additions and 0 deletions.
4 changes: 4 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from qc_openscenario.checks.schema_checker import schema_checker
from qc_openscenario.checks.basic_checker import basic_checker
from qc_openscenario.checks.reference_checker import reference_checker
from qc_openscenario.checks.parameters_checker import parameters_checker

logging.basicConfig(format="%(asctime)s - %(message)s", level=logging.INFO)

Expand Down Expand Up @@ -55,6 +56,9 @@ def main():
# 3. Run reference checks
reference_checker.run_checks(checker_data)

# 4. Run parameters checks
parameters_checker.run_checks(checker_data)

result.write_to_file(
config.get_checker_bundle_param(
checker_bundle_name=constants.BUNDLE_NAME, param_name="resultFile"
Expand Down
5 changes: 5 additions & 0 deletions qc_openscenario/checks/parameters_checker/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from . import parameters_constants as parameters_constants
from . import parameters_checker as parameters_checker
from . import (
valid_parameter_declaration_in_catalogs as valid_parameter_declaration_in_catalogs,
)
64 changes: 64 additions & 0 deletions qc_openscenario/checks/parameters_checker/parameters_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import logging

from lxml import etree

from qc_baselib import Configuration, Result, StatusType

from qc_openscenario import constants
from qc_openscenario.checks import utils, models
from qc_openscenario.schema import schema_files

from qc_openscenario.checks.parameters_checker import (
parameters_constants,
valid_parameter_declaration_in_catalogs,
)


def run_checks(checker_data: models.CheckerData) -> None:
logging.info("Executing parameters checks")

checker_data.result.register_checker(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=parameters_constants.CHECKER_ID,
description="Check if parameters properties of input file are properly set",
summary="",
)

if checker_data.input_file_xml_root is None:
logging.error(
f"Invalid xml input file. Checker {parameters_constants.CHECKER_ID} skipped"
)
checker_data.result.set_checker_status(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=parameters_constants.CHECKER_ID,
status=StatusType.SKIPPED,
)
return

if checker_data.schema_version not in schema_files.SCHEMA_FILES:

logging.error(
f"Version {checker_data.schema_version} unsupported. Checker {parameters_constants.CHECKER_ID} skipped"
)
checker_data.result.set_checker_status(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=parameters_constants.CHECKER_ID,
status=StatusType.SKIPPED,
)
return

rule_list = [valid_parameter_declaration_in_catalogs.check_rule]

for rule in rule_list:
rule(checker_data=checker_data)

logging.info(
f"Issues found - {checker_data.result.get_checker_issue_count(checker_bundle_name=constants.BUNDLE_NAME, checker_id=parameters_constants.CHECKER_ID)}"
)

# TODO: Add logic to deal with error or to skip it
checker_data.result.set_checker_status(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=parameters_constants.CHECKER_ID,
status=StatusType.COMPLETED,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CHECKER_ID = "parameters_xosc"
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import os, logging

from dataclasses import dataclass
from typing import List

from lxml import etree

from qc_baselib import Configuration, Result, IssueSeverity

from qc_openscenario import constants
from qc_openscenario.schema import schema_files
from qc_openscenario.checks import utils, models

from qc_openscenario.checks.parameters_checker import parameters_constants

MIN_RULE_VERSION = "1.2.0"
RULE_SEVERITY = IssueSeverity.ERROR


def check_rule(checker_data: models.CheckerData) -> None:
"""
Rule ID: asam.net:xosc:1.2.0:parameters.valid_parameter_declaration_in_catalogs
Description: All parameters used within a catalog shall be declared within their ParameterDeclaration in the same catalog,
which sets a default value for each parameter.
Severity: ERROR
Version range: [1.2.0, )
Remark:
None
More info at
- https://github.com/asam-ev/qc-openscenarioxml/issues/16
"""
logging.info("Executing valid_parameter_declaration_in_catalogs check")

schema_version = checker_data.schema_version
if schema_version is None:
logging.info(f"- Version not found in the file. Skipping check")
return

if utils.compare_versions(schema_version, MIN_RULE_VERSION) < 0:
logging.info(
f"- Version {schema_version} is less than minimum required version {MIN_RULE_VERSION}. Skipping check"
)
return

rule_uid = checker_data.result.register_rule(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=parameters_constants.CHECKER_ID,
emanating_entity="asam.net",
standard="xosc",
definition_setting=MIN_RULE_VERSION,
rule_full_name="parameters.valid_parameter_declaration_in_catalogs",
)

root = checker_data.input_file_xml_root

catalogs_node = root.findall(".//Catalog")
if catalogs_node is None:
logging.error("Cannot find Catalog nodes in provided XOSC file. Skipping check")
return

print("catalogs_node : ", catalogs_node)

for catalog_node in catalogs_node:

parameter_declaration_nodes = catalog_node.find(".//ParameterDeclarations")
print("parameter_declaration_nodes : ", parameter_declaration_nodes)
# Get parameters declarations and check if they have default value
defined_parameters_with_default = set()
if parameter_declaration_nodes is not None:
for declaration_node in list(parameter_declaration_nodes):
current_name = declaration_node.get("name")
current_default_value = declaration_node.get("value")
print("current_default_value : ", current_default_value)

if (
current_name is not None
and current_default_value is not None
and current_default_value != ""
):
defined_parameters_with_default.add(current_name)

xpath_expr = './/*[starts-with(@*, "$")]'

print("defined_parameters_with_default: ", defined_parameters_with_default)
nodes_with_parameters_attributes = catalog_node.xpath(xpath_expr)
print("nodes_with_parameters_attributes: ", nodes_with_parameters_attributes)

for node_with_parameter_attribute in nodes_with_parameters_attributes:
xpath = root.getpath(node_with_parameter_attribute)

for attr_name, attr_value in node_with_parameter_attribute.attrib.items():
if (
attr_value.startswith("$")
and attr_value[1:] not in defined_parameters_with_default
):

issue_id = checker_data.result.register_issue(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=parameters_constants.CHECKER_ID,
description="Issue flagging when used parameters is not defined or has not default value within a catalog",
level=RULE_SEVERITY,
rule_uid=rule_uid,
)
checker_data.result.add_xml_location(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=parameters_constants.CHECKER_ID,
issue_id=issue_id,
xpath=xpath,
description=f"Parameter {attr_value[1:]} for attribute {attr_name} not defined in Catalog or with no default value",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version='1.0' encoding='UTF-8'?>
<OpenSCENARIO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../qc_openscenario/schema/1.3.0/OpenSCENARIO.xsd">
<FileHeader author="ASAM e.V." date="2021-02-05T18:50:17" description="Simple Overtaker example"
revMajor="1" revMinor="3" />
<Catalog name="PositiveCatalog">
<Vehicle name="Vehicle 1" vehicleCategory="car">
<BoundingBox>
<!-- Inserted rule violation since the parameter "centerBoundingBoxX" was not
declared. -->
<Center x="$centerBoundingBoxX" y="0.0" z="0.75" />
<Dimensions width="1.8" length="4.5" height="1.5" />
</BoundingBox>
<Performance maxSpeed="200.0" maxDeceleration="30.0" maxAcceleration="200.0" />
<Axles>
<FrontAxle positionZ="0.4" trackWidth="1.68" positionX="2.98"
maxSteering="0.5235987756" wheelDiameter="0.8" />
<RearAxle positionZ="0.4" trackWidth="1.68" positionX="0.0"
maxSteering="0.5235987756" wheelDiameter="0.8" />
</Axles>
</Vehicle>
</Catalog>
</OpenSCENARIO>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version='1.0' encoding='UTF-8'?>
<OpenSCENARIO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../qc_openscenario/schema/1.3.0/OpenSCENARIO.xsd">
<FileHeader author="ASAM e.V." date="2021-02-05T18:50:17" description="Simple Overtaker example"
revMajor="1" revMinor="3" />
<Catalog name="PositiveCatalog">
<Vehicle name="Vehicle 1" vehicleCategory="car">
<ParameterDeclarations>
<!-- Inserted rule violation since no default value for a parameter declaration is
provided. -->
<ParameterDeclaration name="centerBoundingBoxX" parameterType="double" value="" />
</ParameterDeclarations>
<BoundingBox>
<Center x="$centerBoundingBoxX" y="0.0" z="0.75" />
<Dimensions width="1.8" length="4.5" height="1.5" />
</BoundingBox>
<Performance maxSpeed="200.0" maxDeceleration="30.0" maxAcceleration="200.0" />
<Axles>
<FrontAxle positionZ="0.4" trackWidth="1.68" positionX="2.98"
maxSteering="0.5235987756" wheelDiameter="0.8" />
<RearAxle positionZ="0.4" trackWidth="1.68" positionX="0.0"
maxSteering="0.5235987756" wheelDiameter="0.8" />
</Axles>
</Vehicle>
</Catalog>
</OpenSCENARIO>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version='1.0' encoding='UTF-8'?>
<OpenSCENARIO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../qc_openscenario/schema/1.3.0/OpenSCENARIO.xsd">
<FileHeader author="ASAM e.V." date="2021-02-05T18:50:17" description="Simple Overtaker example"
revMajor="1" revMinor="3" />
<Catalog name="PositiveCatalog">
<Vehicle name="Vehicle 1" vehicleCategory="car">
<ParameterDeclarations>
<ParameterDeclaration name="centerBoundingBoxX" parameterType="double" value="1.3" />
</ParameterDeclarations>
<BoundingBox>
<Center x="$centerBoundingBoxX" y="0.0" z="0.75" />
<Dimensions width="1.8" length="4.5" height="1.5" />
</BoundingBox>
<Performance maxSpeed="200.0" maxDeceleration="30.0" maxAcceleration="200.0" />
<Axles>
<FrontAxle positionZ="0.4" trackWidth="1.68" positionX="2.98"
maxSteering="0.5235987756" wheelDiameter="0.8" />
<RearAxle positionZ="0.4" trackWidth="1.68" positionX="0.0"
maxSteering="0.5235987756" wheelDiameter="0.8" />
</Axles>
</Vehicle>
</Catalog>
</OpenSCENARIO>
92 changes: 92 additions & 0 deletions tests/test_parameters_checks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import os
import pytest
import test_utils
from qc_openscenario import constants
from qc_openscenario.checks.parameters_checker import parameters_constants
from qc_baselib import Result, IssueSeverity


def test_valid_parameter_declaration_in_catalogs_positive(
monkeypatch,
) -> None:
base_path = "tests/data/valid_parameter_declaration_in_catalogs/"
target_file_name = (
f"parameters.valid_parameter_declaration_in_catalogs.positive.xosc"
)
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)

assert (
len(
result.get_issues_by_rule_uid(
"asam.net:xosc:1.2.0:parameters.valid_parameter_declaration_in_catalogs"
)
)
== 0
)

test_utils.cleanup_files()


def test_valid_parameter_declaration_in_catalogs_negative(
monkeypatch,
) -> None:
base_path = "tests/data/valid_parameter_declaration_in_catalogs/"
target_file_name = (
f"parameters.valid_parameter_declaration_in_catalogs.negative.xosc"
)
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)

_ = result.get_checker_result(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=parameters_constants.CHECKER_ID,
)

reference_issues = result.get_issues_by_rule_uid(
"asam.net:xosc:1.2.0:parameters.valid_parameter_declaration_in_catalogs"
)
assert len(reference_issues) == 1
assert reference_issues[0].level == IssueSeverity.ERROR
test_utils.cleanup_files()


def test_valid_parameter_declaration_in_catalogs_negative_no_default(
monkeypatch,
) -> None:
base_path = "tests/data/valid_parameter_declaration_in_catalogs/"
target_file_name = (
f"parameters.valid_parameter_declaration_in_catalogs.negative_no_default.xosc"
)
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)

_ = result.get_checker_result(
checker_bundle_name=constants.BUNDLE_NAME,
checker_id=parameters_constants.CHECKER_ID,
)

reference_issues = result.get_issues_by_rule_uid(
"asam.net:xosc:1.2.0:parameters.valid_parameter_declaration_in_catalogs"
)
assert len(reference_issues) == 1
assert reference_issues[0].level == IssueSeverity.ERROR
test_utils.cleanup_files()

0 comments on commit 63790e5

Please sign in to comment.