From a550f76d1d7477b7332ec0b4609e4feef0f7b0b9 Mon Sep 17 00:00:00 2001 From: Hossein Rimaz Date: Wed, 6 Dec 2023 15:17:44 +0100 Subject: [PATCH] Fix negative xsd range edge cases (#178) The current implementation uses the `abs()` function to check that the value is inside the range. However, the range is not symmetric. For example, for a [byte](https://www.w3.org/TR/xmlschema11-2/#byte), which is between [-128, 127], the value of [maxInclusive](https://www.w3.org/TR/xmlschema11-2/#dt-maxInclusive) should be 127, and [minInclusive](https://www.w3.org/TR/xmlschema11-2/#dt-minInclusive) should be -128. --- basyx/aas/model/datatypes.py | 12 ++++++++---- test/model/test_datatypes.py | 12 ++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/basyx/aas/model/datatypes.py b/basyx/aas/model/datatypes.py index 0d02e25f3..2925815ba 100644 --- a/basyx/aas/model/datatypes.py +++ b/basyx/aas/model/datatypes.py @@ -261,7 +261,8 @@ class Float(float): class Long(int): def __new__(cls, *args, **kwargs): res = int.__new__(cls, *args, **kwargs) - if abs(res) > 2**63-1: + # [-9223372036854775808, 9223372036854775807] + if res > 2**63-1 or res < -2**63: raise ValueError("{} is out of the allowed range for type {}".format(res, cls.__name__)) return res @@ -269,7 +270,8 @@ def __new__(cls, *args, **kwargs): class Int(int): def __new__(cls, *args, **kwargs): res = int.__new__(cls, *args, **kwargs) - if abs(res) > 2**31-1: + # [-2147483648, 2147483647] + if res > 2**31-1 or res < -2**31: raise ValueError("{} is out of the allowed range for type {}".format(res, cls.__name__)) return res @@ -277,7 +279,8 @@ def __new__(cls, *args, **kwargs): class Short(int): def __new__(cls, *args, **kwargs): res = int.__new__(cls, *args, **kwargs) - if abs(res) > 2**15-1: + # [-32768, 32767] + if res > 2**15-1 or res < -2**15: raise ValueError("{} is out of the allowed range for type {}".format(res, cls.__name__)) return res @@ -285,7 +288,8 @@ def __new__(cls, *args, **kwargs): class Byte(int): def __new__(cls, *args, **kwargs): res = int.__new__(cls, *args, **kwargs) - if abs(res) > 2**7-1: + # [-128,127] + if res > 2**7-1 or res < -2**7: raise ValueError("{} is out of the allowed range for type {}".format(res, cls.__name__)) return res diff --git a/test/model/test_datatypes.py b/test/model/test_datatypes.py index 44946838c..78d7630ab 100644 --- a/test/model/test_datatypes.py +++ b/test/model/test_datatypes.py @@ -18,11 +18,23 @@ def test_parse_int(self) -> None: self.assertEqual(5, model.datatypes.from_xsd("5", model.datatypes.Integer)) self.assertEqual(6, model.datatypes.from_xsd("6", model.datatypes.Byte)) self.assertEqual(7, model.datatypes.from_xsd("7", model.datatypes.NonNegativeInteger)) + self.assertEqual(8, model.datatypes.from_xsd("8", model.datatypes.Long)) + self.assertEqual(9, model.datatypes.from_xsd("9", model.datatypes.Int)) + self.assertEqual(10, model.datatypes.from_xsd("10", model.datatypes.Short)) + self.assertEqual(-123456789012345678901234567890, + model.datatypes.from_xsd("-123456789012345678901234567890", model.datatypes.Integer)) + self.assertEqual(2147483647, model.datatypes.from_xsd("2147483647", model.datatypes.Int)) + self.assertEqual(-2147483648, model.datatypes.from_xsd("-2147483648", model.datatypes.Int)) + self.assertEqual(-32768, model.datatypes.from_xsd("-32768", model.datatypes.Short)) + self.assertEqual(-128, model.datatypes.from_xsd("-128", model.datatypes.Byte)) + self.assertEqual(-9223372036854775808, + model.datatypes.from_xsd("-9223372036854775808", model.datatypes.Long)) def test_serialize_int(self) -> None: self.assertEqual("5", model.datatypes.xsd_repr(model.datatypes.Integer(5))) self.assertEqual("6", model.datatypes.xsd_repr(model.datatypes.Byte(6))) self.assertEqual("7", model.datatypes.xsd_repr(model.datatypes.NonNegativeInteger(7))) + self.assertEqual("-128", model.datatypes.xsd_repr(model.datatypes.Byte(-128))) def test_range_error(self) -> None: with self.assertRaises(ValueError) as cm: