import sys sys.path.append('src/') from protocol_components.dtypes import BprotoFieldBaseType from protocol_components.enumeration import FactoryEnumeration, Enumeration from errors import BprotoDuplicateNameError, BprotoDuplicateEnumValueError, BprotoCompilerError, BprotoEnumBitsizeTooLargeError from nameHandling.base import NameStyleBproto, ComponentName def test_enum_factory(): factory = FactoryEnumeration() factory.add_value("X", 0) factory.add_value("A", 1) factory.add_value("C", 3) factory.add_value("B", 2) factory.add_value("D", None) factory.add_value("E", 5) factory.add_value("F", None) enum = factory.assemble("TestEnum") assert enum.name == "TestEnum" assert enum.values == { NameStyleBproto.fromStr("X"): 0, NameStyleBproto.fromStr("A"): 1, NameStyleBproto.fromStr("B"): 2, NameStyleBproto.fromStr("C"): 3, NameStyleBproto.fromStr("D"): 4, NameStyleBproto.fromStr("E"): 5, NameStyleBproto.fromStr("F"): 6 } assert isinstance(enum.name, ComponentName) assert isinstance(enum.get_name(), ComponentName) assert isinstance(enum.get_identifier(), ComponentName) assert isinstance(list(enum.values.keys())[0], ComponentName) def test_enum_factory_failure_cases_dubplicate_value(): factory = FactoryEnumeration() factory.add_value("X", 0) factory.add_value("Y", 0) factory.add_value("Z", 1) try: factory.assemble("TestEnum") assert False except BprotoCompilerError as e: assert isinstance(e, BprotoDuplicateEnumValueError) def test_enum_factory_failure_cases_duplicate_name(): factory = FactoryEnumeration() factory.add_value("X", 0) factory.add_value("Y", 1) factory.add_value("Y", 2) try: factory.assemble("TestEnum") assert False except BprotoCompilerError as e: assert isinstance(e, BprotoDuplicateNameError) def test_enum_factory_failure_cases_duplicate_name_and_value(): factory = FactoryEnumeration() factory.add_value("X", 0) factory.add_value("X", 0) try: factory.assemble("TestEnum") assert False except BprotoCompilerError as e: assert isinstance(e, BprotoDuplicateNameError) or isinstance(e, BprotoDuplicateEnumValueError) def test_enum_sorted(): factory = FactoryEnumeration() factory.add_value("X", 0) factory.add_value("D", None) factory.add_value("C", 3) factory.add_value("E", 5) factory.add_value("F", None) factory.add_value("B", 2) factory.add_value("A", 1) enum = factory.assemble("TestEnum") assert list(enum.values.values()) == list(range(7)) def test_enum_size_calc(): assert FactoryEnumeration.calculate_bitsize(list(range(17))) == 5 assert FactoryEnumeration.calculate_bitsize(list(range(16))) == 4 assert FactoryEnumeration.calculate_bitsize(list(range(9))) == 4 assert FactoryEnumeration.calculate_bitsize(list(range(8))) == 3 assert FactoryEnumeration.calculate_bitsize(list(range(7))) == 3 assert FactoryEnumeration.calculate_bitsize([1, 2, 31]) == 5 assert FactoryEnumeration.calculate_bitsize([1, 32, 2]) == 6 assert FactoryEnumeration.calculate_bitsize([127, 0, 2]) == 7 assert FactoryEnumeration.calculate_bitsize([]) == 1 def test_enum_auxiliary_data_typemap(): e = Enumeration("TestEnum", 8) assert e.map_auxiliary_datatypes() == BprotoFieldBaseType.UINT8 e = Enumeration("TestEnum", 16) assert e.map_auxiliary_datatypes() == BprotoFieldBaseType.UINT16 e = Enumeration("TestEnum", 24) assert e.map_auxiliary_datatypes() == BprotoFieldBaseType.UINT32 e = Enumeration("TestEnum", 32) assert e.map_auxiliary_datatypes() == BprotoFieldBaseType.UINT32 e = Enumeration("TestEnum", 64) assert e.map_auxiliary_datatypes() == BprotoFieldBaseType.UINT64 e = Enumeration("TestEnum", 65) try: e.map_auxiliary_datatypes() assert False except Exception as err: assert isinstance(err, BprotoEnumBitsizeTooLargeError) def test_enum_size_calculation(): # Uint8 factory = FactoryEnumeration() for i in range(3): factory.add_value(f"#{i}", i) e = factory.assemble("TestEnum") assert e.get_size_bits() == 8 assert e.get_size_bytes() == 1 factory = FactoryEnumeration() for i in range(2**8): factory.add_value(f"#{i}", i) e = factory.assemble("TestEnum") assert e.get_size_bits() == 8 assert e.get_size_bytes() == 1 # Uint16 factory = FactoryEnumeration() for i in range(2**8 + 1): factory.add_value(f"#{i}", i) e = factory.assemble("TestEnum") assert e.get_size_bits() == 16 assert e.get_size_bytes() == 2 factory = FactoryEnumeration() for i in range(2**16): factory.add_value(f"#{i}", i) e = factory.assemble("TestEnum") assert e.get_size_bits() == 16 assert e.get_size_bytes() == 2 # Uint32 factory = FactoryEnumeration() for i in range(17): factory.add_value(f"#{i}", i) factory.add_value(f"#{2**16}", 2**16) # We start couinting from 0 -> 2**16 does not fit in 16 bits e = factory.assemble("TestEnum") assert e.get_size_bits() == 32 assert e.get_size_bytes() == 4 factory = FactoryEnumeration() for i in range(17): factory.add_value(f"#{i}", i) factory.add_value(f"#{2**32 - 1}", 2**32 - 1) # We start couinting from 0 2**32 - 1 does barely fit in 32 bits e = factory.assemble("TestEnum") assert e.get_size_bits() == 32 assert e.get_size_bytes() == 4 # Uint64 factory = FactoryEnumeration() for i in range(17): factory.add_value(f"#{i}", i) factory.add_value(f"#{2**32}", 2**32) # We start couinting from 0 -> 2**32 does not fit in 32 bits e = factory.assemble("TestEnum") assert e.get_size_bits() == 64 assert e.get_size_bytes() == 8 factory = FactoryEnumeration() for i in range(17): factory.add_value(f"#{i}", i) factory.add_value(f"#{2**64 - 1}", 2**64 - 1) # We start couinting from 0 2**64 - 1 does barely fit in 64 bits e = factory.assemble("TestEnum") assert e.get_size_bits() == 64 assert e.get_size_bytes() == 8 # Too large factory = FactoryEnumeration() for i in range(17): factory.add_value(f"#{i}", i) factory.add_value(f"#{2**64}", 2**64) # This can cause rounding errors # log2(2**64) ~ log2(2**64 - 1) ~ 64 # This is btw not a problem for 2**32 # stupid floating point errors # We start couinting from 0 -> 2**64 does not fit in 64 bits try: e = factory.assemble("TestEnum") assert False except Exception as err: assert isinstance(err, BprotoEnumBitsizeTooLargeError)