diff --git a/pcapkit/protocols/misc/pcap/header.py b/pcapkit/protocols/misc/pcap/header.py index 7cba752a40..66e38787c4 100644 --- a/pcapkit/protocols/misc/pcap/header.py +++ b/pcapkit/protocols/misc/pcap/header.py @@ -197,8 +197,8 @@ def make(self, Args: byteorder: header byte order - lilendian: little-endian flag - bigendian: big-endian flag + lilendian: little-endian flag; overrides ``byteorder`` if given + bigendian: big-endian flag; overrides ``byteorder`` if given nanosecond: nanosecond-resolution file flag version: version information version_major: major version number @@ -336,21 +336,20 @@ def _make_magic(self, byteorder: 'Literal["big", "little"]' = sys.byteorder, Args: byteorder: header byte order - lilendian: little-endian flag - bigendian: big-endian flag + lilendian: little-endian flag; overrides ``byteorder`` if given + bigendian: big-endian flag; overrides ``byteorder`` if given nanosecond: nanosecond-resolution file flag Returns: Magic number and little-endian flag. """ - if lilendian is not None and bigendian is not None: - if lilendian == bigendian: - raise EndianError('unresolved byte order') - if bigendian: - return _MAGIC_NUM[('big', nanosecond)], False - if lilendian: - return _MAGIC_NUM[('little', nanosecond)], True + if lilendian is not None and bigendian is not None and lilendian == bigendian: + raise EndianError('unresolved byte order') + if bigendian is not None: + byteorder = 'big' if bigendian else 'little' + elif lilendian is not None: + byteorder = 'little' if lilendian else 'big' if byteorder not in ('little', 'big'): raise EndianError(f"unknown byte order: {byteorder!r}") diff --git a/tests/protocols/misc/pcap/test_header_frame_unit.py b/tests/protocols/misc/pcap/test_header_frame_unit.py index e52a40bac5..3e82807029 100644 --- a/tests/protocols/misc/pcap/test_header_frame_unit.py +++ b/tests/protocols/misc/pcap/test_header_frame_unit.py @@ -146,8 +146,8 @@ class NamedBytesIO(io.BytesIO): (b'\xa1\xb2\xc3\xd4', False)) self.assertEqual(header._make_magic(lilendian=True, bigendian=False), (b'\xd4\xc3\xb2\xa1', True)) - self.assertEqual(header._make_magic(byteorder='big', lilendian='', bigendian=False), # type: ignore[arg-type] - (b'\xa1\xb2\xc3\xd4', False)) + self.assertEqual(header._make_magic(byteorder='big', bigendian=False), + (b'\xd4\xc3\xb2\xa1', True)) with self.assertRaises(EndianError): header._make_magic(lilendian=True, bigendian=True) with self.assertRaises(EndianError): diff --git a/tests/protocols/misc/pcap/test_header_lone_endian_flag_unit.py b/tests/protocols/misc/pcap/test_header_lone_endian_flag_unit.py new file mode 100644 index 0000000000..4942417767 --- /dev/null +++ b/tests/protocols/misc/pcap/test_header_lone_endian_flag_unit.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +import importlib.util +import unittest + +from tests._support import reimport_once_per_class + +RUNTIME_DEPS = ('tbtrim', 'aenum', 'chardet', 'dictdumper') +HAS_RUNTIME = all(importlib.util.find_spec(name) is not None for name in RUNTIME_DEPS) + +BIG = b'\xa1\xb2\xc3\xd4' +LITTLE = b'\xd4\xc3\xb2\xa1' + + +@unittest.skipUnless(HAS_RUNTIME, 'runtime dependencies not installed') +class PCAPHeaderLoneEndianFlagUnitTests(unittest.TestCase): + """A single ``lilendian``/``bigendian`` flag selects the byte order (GH-1144).""" + + def setUp(self) -> None: + reimport_once_per_class(self) + + def test_lone_flag_overrides_byteorder(self) -> None: + from pcapkit.protocols.misc.pcap.header import Header + + # ``byteorder`` is set to the opposite order, so a flag that is ignored + # shows up regardless of the host's own byte order + cases = ( + ({'bigendian': True, 'byteorder': 'little'}, BIG, 'big'), + ({'bigendian': False, 'byteorder': 'big'}, LITTLE, 'little'), + ({'lilendian': True, 'byteorder': 'big'}, LITTLE, 'little'), + ({'lilendian': False, 'byteorder': 'little'}, BIG, 'big'), + ) + for kwargs, magic, byteorder in cases: + with self.subTest(**kwargs): + header = Header(**kwargs) + self.assertEqual(header.data[:4], magic) + self.assertEqual(header.info.magic_number.byteorder, byteorder) + + def test_conflicting_flags_are_rejected(self) -> None: + from pcapkit.protocols.misc.pcap.header import Header + from pcapkit.utilities.exceptions import EndianError + + for flag in (True, False): + with self.subTest(flag=flag): + with self.assertRaises(EndianError): + Header(lilendian=flag, bigendian=flag) + + +if __name__ == '__main__': + unittest.main()