diff --git a/tests/test_types_basic.py b/tests/test_types_basic.py index c91fc10e..13b6e614 100644 --- a/tests/test_types_basic.py +++ b/tests/test_types_basic.py @@ -46,6 +46,14 @@ def test_int_too_short(): t.uint16_t.deserialize(b"\x00") +def test_int_out_of_bounds(): + with pytest.raises(ValueError): + t.uint8_t(-1) + + with pytest.raises(ValueError): + t.uint8_t(0xFF + 1) + + def test_bytes(): data = b"abcde\x00\xff" @@ -95,7 +103,7 @@ class TestList(t.LVList, item_type=t.uint8_t, length_type=t.uint8_t): assert isinstance(d, TestList) - with pytest.raises(OverflowError): + with pytest.raises(ValueError): TestList([1, 2, 0xFFFF, 4]).serialize() diff --git a/zigpy_znp/types/basic.py b/zigpy_znp/types/basic.py index 7afb2b1f..f9cf476e 100644 --- a/zigpy_znp/types/basic.py +++ b/zigpy_znp/types/basic.py @@ -28,8 +28,21 @@ class int_t(int): _signed = True _size = None + def __new__(cls, value): + instance = int.__new__(cls, value) + + if instance._signed is not None and instance._size is not None: + # It's a concrete int_t type, check to make sure it's valid + instance.serialize() + + return instance + def serialize(self) -> bytes: - return self.to_bytes(self._size, "little", signed=self._signed) + try: + return self.to_bytes(self._size, "little", signed=self._signed) + except OverflowError as e: + # OverflowError is not a subclass of ValueError, making it annoying to catch + raise ValueError(str(e)) from e @classmethod def deserialize(cls, data: bytes) -> typing.Tuple["int_t", bytes]: