Skip to content

Commit

Permalink
structures: ensure that no unknown parameters are specified for `enco…
Browse files Browse the repository at this point in the history
…de()`

Signed-off-by: Andreas Lauser <[email protected]>
Signed-off-by: Gerrit Ecke <[email protected]>
  • Loading branch information
andlaus committed Feb 6, 2024
1 parent bec5e92 commit a340041
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 13 deletions.
Binary file modified examples/somersault.pdx
Binary file not shown.
12 changes: 12 additions & 0 deletions examples/somersaultecu.py
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,18 @@ class SomersaultSID(IntEnum):
bit_position=None,
sdgs=[],
),
ValueParameter(
short_name="sault_time",
long_name=None,
semantic=None,
description=None,
physical_default_value_raw="255",
byte_position=2,
dop_ref=OdxLinkRef("somersault.DOP.duration", doc_frags),
dop_snref=None,
bit_position=None,
sdgs=[],
),
]),
byte_size=None,
),
Expand Down
9 changes: 8 additions & 1 deletion odxtools/basicstructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from .dataobjectproperty import DataObjectProperty
from .decodestate import DecodeState
from .encodestate import EncodeState
from .exceptions import DecodeError, EncodeError, OdxWarning, odxassert, odxraise
from .exceptions import DecodeError, EncodeError, OdxWarning, odxassert, odxraise, strict_mode
from .nameditemlist import NamedItemList
from .odxlink import OdxDocFragment, OdxLinkDatabase, OdxLinkId
from .odxtypes import ParameterDict, ParameterValue, ParameterValueDict
Expand Down Expand Up @@ -124,6 +124,13 @@ def convert_physical_to_internal(self,
f"Expected a dictionary for the values of structure {self.short_name}, "
f"got {type(param_value)}")

# in strict mode, ensure that no values for unknown parameters are specified.
if strict_mode:
param_names = [param.short_name for param in self.parameters]
for param_key in param_value:
if param_key not in param_names:
odxraise(f"Value for unknown parameter '{param_key}' specified")

encode_state = EncodeState(
b'',
dict(param_value),
Expand Down
42 changes: 30 additions & 12 deletions tests/test_somersault.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: MIT
import unittest

from odxtools.exceptions import odxrequire
from odxtools.exceptions import OdxError, odxrequire
from odxtools.load_pdx_file import load_pdx_file
from odxtools.parameters.nrcconstparameter import NrcConstParameter

Expand Down Expand Up @@ -145,9 +145,11 @@ def test_somersault_lazy(self) -> None:
self.assertEqual([x.short_name for x in service.negative_responses], ["flips_not_done"])

pr = service.positive_responses.grudging_forward
self.assertEqual([x.short_name for x in pr.parameters], ["sid", "num_flips_done"])
self.assertEqual([x.short_name for x in pr.parameters],
["sid", "num_flips_done", "sault_time"])
self.assertEqual([x.short_name for x in pr.required_parameters], [])
self.assertEqual(pr.get_static_bit_length(), 16)
self.assertEqual([x.short_name for x in pr.free_parameters], ["sault_time"])
self.assertEqual(pr.get_static_bit_length(), 24)

nr = service.negative_responses.flips_not_done
self.assertEqual(
Expand All @@ -162,7 +164,16 @@ def test_somersault_lazy(self) -> None:
self.assertEqual(nrc_const.coded_values, [0, 1, 2])


class TestDecode(unittest.TestCase):
class TestEnDecode(unittest.TestCase):

def test_encode_specify_unknown_param(self) -> None:
ecu = odxdb.ecus.somersault_lazy
service = ecu.services.do_forward_flips
request = odxrequire(service.request)
with self.assertRaises(OdxError) as eo:
request.encode(forward_soberness_check=0x12, num_flips=5, grass_level="what grass?")

self.assertEqual(str(eo.exception), "Value for unknown parameter 'grass_level' specified")

def test_decode_request(self) -> None:
messages = odxdb.ecus.somersault_assiduous.decode(bytes([0x03, 0x45]))
Expand Down Expand Up @@ -226,9 +237,9 @@ def test_code_table_params(self) -> None:
dizzyness_level=42,
happiness_level=92,
last_pos_response=("forward_grudging", {
"dizzyness_level": 42
"sault_time": 249
}))
self.assertEqual(resp_data.hex(), "622a5c03fa7b")
self.assertEqual(resp_data.hex(), "622a5c03fa7bf9")

decoded_resp_data = pr.decode(resp_data)
assert isinstance(decoded_resp_data, dict)
Expand All @@ -241,21 +252,24 @@ def test_code_table_params(self) -> None:
self.assertEqual(
set(decoded_resp_data["last_pos_response"]
[1].keys()), # type: ignore[index, union-attr]
{"sid", "num_flips_done"})
{"sid", "num_flips_done", "sault_time"})
# the num_flips_done parameter is a matching request parameter
# for this response, so it produces a binary blob. possibly,
# it should be changed to a ValueParameter...
self.assertEqual(
decoded_resp_data["last_pos_response"][1] # type: ignore[index, call-overload]
["num_flips_done"], # type: ignore[index, call-overload]
bytes([123]))
self.assertEqual(
decoded_resp_data["last_pos_response"][1] # type: ignore[index, call-overload]
["sault_time"], # type: ignore[index, call-overload]
249)

# test the "backward flips grudgingly done" response
resp_data = pr.encode(
dizzyness_level=75,
happiness_level=3,
last_pos_response=("backward_grudging", {
'dizzyness_level': 75,
'num_flips_done': 5,
'grumpiness_level': 150
}))
Expand Down Expand Up @@ -310,14 +324,14 @@ def test_free_param_info(self) -> None:

with patch("sys.stdout", stdout):
pos_response.print_free_parameters_info()
expected_output = "forward_soberness_check: uint8\nnum_flips: uint8\n"
expected_output = "forward_soberness_check: uint8\nnum_flips: uint8\nsault_time: uint8\n"
actual_output = stdout.getvalue()
self.assertEqual(actual_output, expected_output)

with patch("sys.stdout", stdout):
neg_response.print_free_parameters_info()
expected_output = (
"forward_soberness_check: uint8\nnum_flips: uint8\nflips_successfully_done: uint8\n"
"forward_soberness_check: uint8\nnum_flips: uint8\nsault_time: uint8\nflips_successfully_done: uint8\n"
)
actual_output = stdout.getvalue()
self.assertEqual(actual_output, expected_output)
Expand All @@ -336,9 +350,13 @@ def test_decode_response(self) -> None:
f"There should be only one service for 0x0145 but there are: {messages}",
)
m = messages[0]
self.assertEqual(m.coded_message, bytes([0xFA, 0x03]))
self.assertEqual(m.coded_message.hex(), "fa03ff")
self.assertEqual(m.coding_object, pos_response)
self.assertEqual(m.param_dict, {"sid": 0xFA, "num_flips_done": bytearray([0x03])})
self.assertEqual(m.param_dict, {
"sid": 0xFA,
"num_flips_done": bytearray([0x03]),
"sault_time": 255
})


class TestNavigation(unittest.TestCase):
Expand Down

0 comments on commit a340041

Please sign in to comment.