From 098d62d1a15c6e9f114f3f206158f1a221ede856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 5 May 2026 22:15:41 +0200 Subject: [PATCH 1/2] Add unit tests for Variable class. --- test/test_od.py | 4 +++ test/test_sdo.py | 3 ++ test/test_variable.py | 65 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 test/test_variable.py diff --git a/test/test_od.py b/test/test_od.py index 231a58dd..2f79b918 100644 --- a/test/test_od.py +++ b/test/test_od.py @@ -260,6 +260,10 @@ def test_get_item_index(self): self.assertIsInstance(item, od.ODArray) self.assertIs(item, array) + def test_get_variable_not_found(self): + test_od = od.ObjectDictionary() + self.assertIsNone(test_od.get_variable(0x9999)) + class TestArray(unittest.TestCase): diff --git a/test/test_sdo.py b/test/test_sdo.py index a9418716..ebf7a8f3 100644 --- a/test/test_sdo.py +++ b/test/test_sdo.py @@ -54,6 +54,9 @@ def test_array_contains_non_int(self): self.assertNotIn("not an int", array) self.assertNotIn(None, array) + def test_get_variable_not_found(self): + self.assertIsNone(self.sdo_node.get_variable(0x9999)) + class TestSDO(unittest.TestCase): """ diff --git a/test/test_variable.py b/test/test_variable.py new file mode 100644 index 00000000..51250bd1 --- /dev/null +++ b/test/test_variable.py @@ -0,0 +1,65 @@ +import unittest + +from canopen import objectdictionary as od +from canopen.variable import Variable + + +class _StubVariable(Variable): + """Minimal concrete Variable for testing read/write/bits.""" + + def __init__(self, od_var): + super().__init__(od_var) + self._data = od_var.encode_raw(od_var.default) + + def get_data(self): + return self._data + + def set_data(self, data): + self._data = data + + +class TestVariable(unittest.TestCase): + + def test_read_invalid_format(self): + var = od.ODVariable("Test UNSIGNED8", 0x1000) + var.data_type = od.UNSIGNED8 + var.default = 0 + v = _StubVariable(var) + with self.assertRaises(ValueError): + v.read(fmt="invalid") + + def test_write_desc(self): + var = od.ODVariable("Test UNSIGNED8", 0x1000) + var.data_type = od.UNSIGNED8 + var.default = 0 + var.add_value_description(0, "Off") + var.add_value_description(1, "On") + v = _StubVariable(var) + v.write("On", fmt="desc") + self.assertEqual(v.raw, 1) + + def test_raw_with_string_value(self): + var = od.ODVariable("Test VISIBLE_STRING", 0x1000) + var.data_type = od.VISIBLE_STRING + var.default = "hello" + var.add_value_description(0, "Off") + v = _StubVariable(var) + # String value must not be looked up in value_descriptions + self.assertEqual(v.raw, "hello") + + def test_bits(self): + var = od.ODVariable("Test UNSIGNED8", 0x1000) + var.data_type = od.UNSIGNED8 + var.default = 0 + var.add_bit_definition("BIT 0", [0]) + var.add_bit_definition("BIT 2 and 3", [2, 3]) + v = _StubVariable(var) + v.raw = 5 + bits = v.bits + self.assertEqual(bits[0], 1) + bits[0] = 0 + self.assertEqual(v.raw, 4) + + +if __name__ == "__main__": + unittest.main() From e592546b045b95e5c321f404787308736cc7ea16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Tue, 5 May 2026 22:24:40 +0200 Subject: [PATCH 2/2] Raise ValueError on invalid fmt argument. --- canopen/variable.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/canopen/variable.py b/canopen/variable.py index d2538c3f..639a1839 100644 --- a/canopen/variable.py +++ b/canopen/variable.py @@ -135,6 +135,7 @@ def read(self, fmt: str = "raw") -> Union[int, bool, float, str, bytes]: :returns: The value of the variable. + :raises ValueError: For unsupported fmt values. """ if fmt == "raw": return self.raw @@ -142,6 +143,7 @@ def read(self, fmt: str = "raw") -> Union[int, bool, float, str, bytes]: return self.phys elif fmt == "desc": return self.desc + raise ValueError(f"Invalid format '{fmt}'") def write( self, value: Union[int, bool, float, str, bytes], fmt: str = "raw"