Fixed bug in composition_yaml.py

Introduced in c77107375f

Limited the xml string before extending it with longer xml character
replacements

Change-Id: I45a39fdf6454746c3df64a0c6a9410b24c0f94a1
This commit is contained in:
Henrik Wahlqvist
2025-08-27 10:04:52 +02:00
parent 7d07b8dec1
commit 7dc2e36c2b
3 changed files with 80 additions and 19 deletions

View File

@@ -88,30 +88,33 @@ class CompositionYaml(ProblemLogger):
return float(value_str[:-1])
return int(value_str)
@staticmethod
def _prepare_for_xml(string):
def _prepare_for_xml(self, signal_name, string):
"""Prepare a string for XML serialization.
Args:
signal_name (str): The name of the signal.
string (str): The string to prepare.
Returns:
xml_string (str): The prepared string.
"""
limited_string = string[:255]
no_line_breaks_string = "".join(limited_string.splitlines())
xml_string = scalarstring.DoubleQuotedScalarString(
no_line_breaks_string.replace(
"&", "&"
).replace(
"<", "&lt;"
).replace(
">", "&gt;"
).replace(
"'", "&apos;"
).replace(
'"', "&quot;"
)
)
illegal_xml_characters = {
"&": "&amp;", # needs to be first in list
"<": "&lt;",
">": "&gt;",
"'": "&apos;",
'"': "&quot;"
}
xml_string_tmp = "".join(string.splitlines())
for char, replacement in illegal_xml_characters.items():
xml_string_tmp = xml_string_tmp.replace(char, replacement)
if len(xml_string_tmp) > 255:
self.warning(f"Converted description for {signal_name} exceeds 255 characters and will be truncated.")
for replacement in illegal_xml_characters.values():
found = xml_string_tmp.find(replacement, 255-len(replacement), 255+len(replacement))
if found < 255 and found + len(replacement) > 255:
xml_string_tmp = xml_string_tmp[:found]
xml_string_tmp = xml_string_tmp[:255] # Since "found" is always < 255 this is safe
xml_string = scalarstring.DoubleQuotedScalarString(xml_string_tmp)
return xml_string
def get_base_data_types(self):
@@ -703,7 +706,7 @@ class CompositionYaml(ProblemLogger):
"init": self.calibration_init_values.get(signal_name, max(min(0, upper), lower)),
}
if info["description"]:
class_info[signal_name]["longname"] = self._prepare_for_xml(info["description"])
class_info[signal_name]["longname"] = self._prepare_for_xml(signal_name, info["description"])
return class_info, data_types
if isinstance(lower, list) or isinstance(upper, list):
@@ -812,6 +815,6 @@ class CompositionYaml(ProblemLogger):
"init": init,
}
if info["description"]:
class_info[signal_name]["longname"] = self._prepare_for_xml(info["description"])
class_info[signal_name]["longname"] = self._prepare_for_xml(signal_name, info["description"])
data_types = {**data_types, **new_data_type}
return class_info, data_types

View File

@@ -0,0 +1,38 @@
# Copyright 2024 Volvo Car Corporation
# Licensed under Apache 2.0.
"""Unit test data for powertrain_build.zone_controller.composition_yaml."""
description = "This is a valid description."
illegal_description = "This is a description with 'single' and \"double\" quotes & some <illegal> XML characters."
fixed_illegal_description = "This is a description with &apos;single&apos; and &quot;double&quot; quotes &amp; some &lt;illegal&gt; XML characters."
long_description = (
"This is a long description that spans multiple lines. \n"
"It does not contain any single and double quotes or any other illegal XML characters. \n"
"Adding a lot of random text to make it longer than 255 characters... \n"
"dummy-text, dummy-text, dummy-text, dummy-text, dummy-text, dummy-text, dummy-text, dummy-text..."
)
long_illegal_description = (
"This is a long description that spans multiple lines. \n"
"It can contain 'single' and \"double\" quotes, & <illegal> XML characters. \n"
"Adding a lot of random text to make it longer than 255 characters... \n"
"dummy-text, dummy-text, dummy-text, dummy-text, dummy-text, dummy-text, dummy-text, dummy-text..."
)
fixed_long_illegal_description = (
"This is a long description that spans multiple lines. "
"It can contain &apos;single&apos; and &quot;double&quot; quotes, &amp; &lt;illegal&gt; XML characters. "
"Adding a lot of random text to make it longer than 255 characters... "
"dummy-text, dummy-text, dummy"
)
long_illegal_description_truncated_tag = (
"This is a long description that spans multiple lines. \n"
"It can contain 'single' and \"double\" quotes, & <illegal> XML characters. \n"
"Adding a lot of random text to make it longer than 255 characters... \n"
"dummy-text & dummy-text & dummy-text & dummy-text & dummy-text & dummy-text & dummy-text & dummy-text..."
)
fixed_long_illegal_description_truncated_tag = (
"This is a long description that spans multiple lines. "
"It can contain &apos;single&apos; and &quot;double&quot; quotes, &amp; &lt;illegal&gt; XML characters. "
"Adding a lot of random text to make it longer than 255 characters... "
"dummy-text &amp; dummy-text "
)

View File

@@ -24,6 +24,7 @@ from test_data.zone_controller.test_composition_yaml import (
composition_yaml_with_dtcs,
composition_yaml_with_external_io,
composition_yaml_with_nvm,
prepare_for_xml,
)
SRC_DIR = Path(__file__).parent
@@ -161,6 +162,25 @@ class TestCompositionYaml(unittest.TestCase):
self.build_cfg, self.signal_interfaces, self.unit_cfg, self.zc_core, self.zc_dids, self.nvm_def, {}, {}
)
def test_prepare_for_xml(self):
"""Checking that the XML preparation is done correctly."""
# Normal
result = self.composition_yaml._prepare_for_xml("dummy", prepare_for_xml.description)
self.assertEqual(result, prepare_for_xml.description)
# Illegal
result = self.composition_yaml._prepare_for_xml("dummy", prepare_for_xml.illegal_description)
self.assertEqual(result, prepare_for_xml.fixed_illegal_description)
# Long normal
result = self.composition_yaml._prepare_for_xml("dummy", prepare_for_xml.long_description)
expected = "".join(prepare_for_xml.long_description.splitlines())[:255]
self.assertEqual(result, expected)
# Long illegal
result = self.composition_yaml._prepare_for_xml("dummy", prepare_for_xml.long_illegal_description)
self.assertEqual(result, prepare_for_xml.fixed_long_illegal_description)
# Long illegal description which is truncated in the middle of an XML tag
result = self.composition_yaml._prepare_for_xml("dummy", prepare_for_xml.long_illegal_description_truncated_tag)
self.assertEqual(result, prepare_for_xml.fixed_long_illegal_description_truncated_tag)
def test_composition_yaml(self):
"""Checking that the dict is generated correctly"""
result = self.composition_yaml.gather_yaml_info()