
Note that this only applies to the runnable in the generated yaml file. Change-Id: I11eea48b41801d3a0dfc479b6cc489108659bb55
254 lines
11 KiB
Python
254 lines
11 KiB
Python
# Copyright 2024 Volvo Car Corporation
|
|
# Licensed under Apache 2.0.
|
|
|
|
"""Unit test script for powertrain_build.zone_controller.generate_yaml."""
|
|
|
|
import copy
|
|
import os
|
|
import unittest
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from powertrain_build.build_proj_config import BuildProjConfig
|
|
from powertrain_build.core import ZCCore
|
|
from powertrain_build.dids import ZCDIDs
|
|
from powertrain_build.unit_configs import UnitConfigs
|
|
from powertrain_build.zone_controller.composition_yaml import CompositionYaml
|
|
from test_data.zone_controller.test_composition_yaml import (
|
|
composition_yaml_setup,
|
|
composition_yaml,
|
|
composition_yaml_with_a2l_axis_data,
|
|
composition_yaml_with_calls_all_fields,
|
|
composition_yaml_with_calls_no_optional_fields,
|
|
composition_yaml_with_dids,
|
|
composition_yaml_with_dtcs,
|
|
)
|
|
|
|
SRC_DIR = Path(__file__).parent
|
|
|
|
|
|
class BuildProjConfigMock(BuildProjConfig):
|
|
"""Class mocking BuildProjConfig."""
|
|
name = ""
|
|
|
|
|
|
def mock_get_composition_config_default(key):
|
|
"""Function to mock BuildProjConfig.get_composition_config."""
|
|
return {
|
|
"compositionArxml": "some_arxml.arxml",
|
|
"compositionName": "compositionName",
|
|
'compositionEnding': 'yml',
|
|
"softwareComponentName": "testName_SC",
|
|
"softwareComponentTemplate": "ARTCSC",
|
|
"softwareComponentBase": "QM",
|
|
"customYamlInitFunctionName": None,
|
|
"customYamlStepFunctionName": None,
|
|
"generateExternalImplementationType": True,
|
|
'includeStatic': True,
|
|
'includeShared': True,
|
|
'includeDiagnostics': True,
|
|
}[key]
|
|
|
|
|
|
def mock_get_composition_config_custom_names(key):
|
|
"""Function to mock BuildProjConfig.get_composition_config."""
|
|
return {
|
|
"compositionArxml": "some_arxml.arxml",
|
|
"compositionName": "compositionName",
|
|
'compositionEnding': 'yml',
|
|
"softwareComponentName": "testName_SC",
|
|
"softwareComponentTemplate": "ARTCSC",
|
|
"softwareComponentBase": "QM",
|
|
"customYamlInitFunctionName": "dummy_init",
|
|
"customYamlStepFunctionName": "dummy_step",
|
|
"generateExternalImplementationType": True,
|
|
'includeStatic': True,
|
|
'includeShared': True,
|
|
'includeDiagnostics': True,
|
|
}[key]
|
|
|
|
|
|
class TestCompositionYaml(unittest.TestCase):
|
|
"""Test case for testing composition_yaml."""
|
|
|
|
def setUp(self):
|
|
"""Set-up common data structures for all tests in the test case."""
|
|
self.build_cfg = MagicMock(spec_set=BuildProjConfigMock)
|
|
self.build_cfg.get_composition_config.side_effect = mock_get_composition_config_default
|
|
self.build_cfg.name = "XVC"
|
|
self.build_cfg.get_scheduler_prefix = MagicMock(return_value="prefix_")
|
|
self.build_cfg.get_src_code_dst_dir = MagicMock(
|
|
return_value=os.path.abspath("output")
|
|
)
|
|
self.build_cfg.get_units_raster_cfg = MagicMock(
|
|
return_value=({"SampleTimes": {"testRunnable": 10}})
|
|
)
|
|
self.build_cfg.get_code_generation_config = MagicMock(return_value=False)
|
|
|
|
self.unit_cfg = MagicMock(spec_set=UnitConfigs)
|
|
self.unit_cfg.get_per_cfg_unit_cfg.return_value = copy.deepcopy(
|
|
composition_yaml_setup.get_per_cfg_unit_cfg_return_value
|
|
)
|
|
|
|
with patch.object(ZCCore, "_get_project_dtcs", return_value=set()):
|
|
self.zc_core = ZCCore(self.build_cfg, self.unit_cfg)
|
|
|
|
with patch.object(ZCDIDs, "_get_project_dids", return_value={}):
|
|
self.zc_dids = ZCDIDs(self.build_cfg, self.unit_cfg)
|
|
|
|
self.zc_spec = copy.deepcopy(composition_yaml_setup.zc_spec)
|
|
|
|
self.calibration_definitions = copy.deepcopy(composition_yaml_setup.calibration_definitions)
|
|
|
|
with patch.object(
|
|
CompositionYaml,
|
|
"_get_all_calibration_definitions",
|
|
return_value=self.calibration_definitions
|
|
):
|
|
self.composition_yaml = CompositionYaml(
|
|
self.build_cfg, self.zc_spec, self.unit_cfg, self.zc_core, self.zc_dids, {}
|
|
)
|
|
|
|
def test_check_unsupported_fields(self):
|
|
"""Test CompositionYaml.check_unsupported_fields."""
|
|
self.composition_yaml.warning = MagicMock()
|
|
test_data = {
|
|
"name": "sVcGpaDemo_D_BrkCtrlr",
|
|
"type": "UInt8",
|
|
"class": "CVC_DISP",
|
|
"lsb": 1,
|
|
"offset": "-",
|
|
"width": 1,
|
|
}
|
|
self.composition_yaml.check_unsupported_fields("dummy", test_data)
|
|
self.composition_yaml.warning.assert_not_called()
|
|
test_data["lsb"] = 10
|
|
self.composition_yaml.check_unsupported_fields("dummy", test_data)
|
|
self.composition_yaml.warning.assert_called_once()
|
|
|
|
def test_composition_yaml(self):
|
|
"""Checking that the dict is generated correctly"""
|
|
result = self.composition_yaml.gather_yaml_info()
|
|
self.assertDictEqual(composition_yaml.expected_result, result)
|
|
|
|
def test_composition_yaml_with_custom_names(self):
|
|
"""Checking that the dict is generated correctly with custom names."""
|
|
self.build_cfg.get_composition_config.side_effect = mock_get_composition_config_custom_names
|
|
self.composition_yaml = CompositionYaml(
|
|
self.build_cfg, self.zc_spec, self.unit_cfg, self.zc_core, self.zc_dids, {}
|
|
)
|
|
result = self.composition_yaml.gather_yaml_info()
|
|
self.assertDictEqual(composition_yaml.expected_custom_names_result, result)
|
|
|
|
def test_composition_yaml_with_calibration(self):
|
|
"""Checking that the dict is generated correctly including calibration data,
|
|
setting generateCalibrationInterfaceFiles to true (sort of)."""
|
|
self.build_cfg.get_code_generation_config = MagicMock(return_value=True)
|
|
with patch.object(
|
|
CompositionYaml,
|
|
"_get_all_calibration_definitions",
|
|
return_value=self.calibration_definitions
|
|
):
|
|
self.composition_yaml = CompositionYaml(
|
|
self.build_cfg, self.zc_spec, self.unit_cfg, self.zc_core, self.zc_dids, {}
|
|
)
|
|
result = self.composition_yaml.gather_yaml_info()
|
|
self.assertDictEqual(composition_yaml.expected_cal_result, result)
|
|
|
|
def test_composition_yaml_with_a2l_axis_data(self):
|
|
"""Checking that the dict is generated correctly, including a2l axis data."""
|
|
self.unit_cfg.get_per_cfg_unit_cfg.return_value = \
|
|
composition_yaml_with_a2l_axis_data.get_per_cfg_unit_cfg_return_value
|
|
a2l_axis_data = composition_yaml_with_a2l_axis_data.a2l_axis_data
|
|
calibration_definitions = \
|
|
self.calibration_definitions + composition_yaml_with_a2l_axis_data.calibration_definitions
|
|
with patch.object(CompositionYaml, "_get_all_calibration_definitions", return_value=calibration_definitions):
|
|
self.composition_yaml = CompositionYaml(
|
|
self.build_cfg, self.zc_spec, self.unit_cfg, self.zc_core, self.zc_dids, a2l_axis_data
|
|
)
|
|
|
|
result = self.composition_yaml.gather_yaml_info()
|
|
self.assertDictEqual(composition_yaml_with_a2l_axis_data.expected_result, result)
|
|
|
|
def test_composition_yaml_with_calls_all_fields(self):
|
|
"""Checking that the dict is generated correctly, with calls including all fields."""
|
|
self.zc_spec["calls"] = {
|
|
"CallOne": {
|
|
"interface": "InterfaceOne",
|
|
"direction": "IN",
|
|
"operation": "OperationOne",
|
|
"timeout": 0.1,
|
|
}
|
|
}
|
|
with patch.object(
|
|
CompositionYaml,
|
|
"_get_all_calibration_definitions",
|
|
return_value=self.calibration_definitions
|
|
):
|
|
self.composition_yaml = CompositionYaml(
|
|
self.build_cfg, self.zc_spec, self.unit_cfg, self.zc_core, self.zc_dids, {}
|
|
)
|
|
result = self.composition_yaml.gather_yaml_info()
|
|
self.assertDictEqual(composition_yaml_with_calls_all_fields.expected_result, result)
|
|
|
|
def test_composition_yaml_with_calls_no_optional_fields(self):
|
|
"""Checking that the dict is generated correctly, with calls without optional fields."""
|
|
self.zc_spec["calls"] = {
|
|
"CallOne": {
|
|
"direction": "IN",
|
|
"operation": "OperationOne",
|
|
}
|
|
}
|
|
with patch.object(
|
|
CompositionYaml,
|
|
"_get_all_calibration_definitions",
|
|
return_value=self.calibration_definitions
|
|
):
|
|
self.composition_yaml = CompositionYaml(
|
|
self.build_cfg, self.zc_spec, self.unit_cfg, self.zc_core, self.zc_dids, {}
|
|
)
|
|
result = self.composition_yaml.gather_yaml_info()
|
|
self.assertDictEqual(composition_yaml_with_calls_no_optional_fields.expected_result, result)
|
|
|
|
def test_composition_yaml_with_dids(self):
|
|
"""Checking that the dict is generated correctly, with DIDs."""
|
|
self.zc_dids.project_dids = {"DID1": {"type": "UInt8"}}
|
|
self.zc_spec["diagnostics"] = composition_yaml_with_dids.diagnostics
|
|
with patch.object(
|
|
CompositionYaml,
|
|
"_get_all_calibration_definitions",
|
|
return_value=self.calibration_definitions
|
|
):
|
|
self.composition_yaml = CompositionYaml(
|
|
self.build_cfg, self.zc_spec, self.unit_cfg, self.zc_core, self.zc_dids, {}
|
|
)
|
|
result = self.composition_yaml.gather_yaml_info()
|
|
self.assertDictEqual(composition_yaml_with_dids.expected_result, result)
|
|
|
|
def test_composition_yaml_with_dtcs(self):
|
|
"""Checking that the dict is generated correctly, with DTCs."""
|
|
self.zc_core.project_dtcs = {"DTC1"}
|
|
self.zc_spec["diagnostics"] = composition_yaml_with_dtcs.diagnostics
|
|
with patch.object(
|
|
CompositionYaml,
|
|
"_get_all_calibration_definitions",
|
|
return_value=self.calibration_definitions
|
|
):
|
|
self.composition_yaml = CompositionYaml(
|
|
self.build_cfg, self.zc_spec, self.unit_cfg, self.zc_core, self.zc_dids, {}
|
|
)
|
|
result = self.composition_yaml.gather_yaml_info()
|
|
self.assertDictEqual(composition_yaml_with_dtcs.expected_result, result)
|
|
|
|
def test_get_init_values_expecting_failure(self):
|
|
"""Test CompositionYaml.get_init_values with a non-existing calibration definition."""
|
|
self.composition_yaml.clear_log()
|
|
json_variables = {"signal_name": "dummy"}
|
|
c_definitions = ["CVC_CAL Float32 signal_name_other = 1.F; "]
|
|
with patch.object(CompositionYaml, "_get_all_calibration_definitions", return_value=c_definitions):
|
|
init_values = self.composition_yaml.get_init_values(json_variables)
|
|
logged_problems = self.composition_yaml.get_problems()
|
|
self.assertEqual(init_values, {})
|
|
self.assertEqual(logged_problems["warning"], [])
|
|
self.assertEqual(logged_problems["critical"], ["Missing init values for calibration variables:\nsignal_name"])
|