import struct import pytest from enum import Enum from pybusmonitor1553.lib1553.fields import Field, BitField, EnumField, ScaledField, ASCIIField from pybusmonitor1553.lib1553.message_base import MessageBase from pybusmonitor1553.lib1553.messages.msg_a3 import MsgA3 from pybusmonitor1553.lib1553.messages.msg_a5 import MsgA5 def test_descriptor_returns_self_on_class_access(): class M(MessageBase): bf = BitField(word_index=0, start_bit=0, width=1) # Accessing via class should return the descriptor itself assert isinstance(M.bf, BitField) def test_enumfield_auto_width_and_fallback(): class E(Enum): A = 0 B = 1 C = 3 class M(MessageBase): ef = EnumField(word_index=0, start_bit=0, enum_cls=E) # width auto # Width auto-calculated to fit max value (3 -> 2 bits) assert M.ef.width == 2 m = M() # Set raw value directly to an undefined value (e.g., 2) m.data[0] = 2 << (16 - (0 + M.ef.width)) # Should return raw int because 2 not in Enum assert m.ef == 2 def test_asciifield_nonprintable_and_validation(): class M(MessageBase): a = ASCIIField(word_index=0) m = M() # write a raw word with non-printable bytes 0x00 0x01 m._data[0] = (0 << 8) | 1 assert m.a == '??' with pytest.raises(ValueError): m.a = 'X' # too short def test_message_base_pack_unpack_and_clamp(): class M(MessageBase): pass m = M() # set some sample words for i in range(32): m._data[i] = i packed = m.pack() assert len(packed) == 64 # create raw with more than 32 words (e.g., 40 words) extra = struct.pack('>40H', *list(range(40))) m2 = M() m2.unpack(extra) # only first 32 should be loaded assert m2._data[31] == 31 def test_msg_a3_25bit_signed_and_ascii(): m = MsgA3() # positive raw raw_25 = 0x00ABCDE msw = (raw_25 >> 9) & 0xFFFF lsw_fragment = raw_25 & 0x1FF m._data[2] = msw m._data[3] = (lsw_fragment << 7) assert isinstance(m.wp1_latitude, float) # negative value: set sign bit of 25-bit value neg_raw = (1 << 24) | 12345 msw = (neg_raw >> 9) & 0xFFFF lsw_fragment = neg_raw & 0x1FF m._data[4] = msw m._data[5] = (lsw_fragment << 7) val = m.wp1_longitude assert isinstance(val, float) # ASCII fields m.hpt_callsign_ab = 'AA' assert m.hpt_callsign_ab == 'AA' def test_msg_a5_32bit_signed_scaled_velocity(): m = MsgA5() # build a negative 32-bit raw value raw32 = (1 << 31) | 12345678 # sign bit set msw = (raw32 >> 16) & 0xFFFF lsw = raw32 & 0xFFFF m._data[2] = msw m._data[3] = lsw expected = float((raw32 - (1 << 32)) * 3.81470e-6) assert pytest.approx(m.velocity_x, rel=1e-9) == expected