test(s7): live python-snap7 coverage for the #632/#638 codecs, TSAP override and PDU size (#632)

Extends the s7_1500 profile (DB1 2048 bytes, 'hex' seed type) with distinct
non-zero seeds for STRING/WSTRING/CHAR/WCHAR/DTL/DATE/TOD/TIME/S5TIME plus
undecodable buffers; S7_1500CodecTests covers reads, BadOutOfRange paths,
write round-trips (S7_SIM_ALLOW_WRITES=1), TSAP keys and negotiated PDU size.
Skips when S7_SIM_ENDPOINT is unreachable.

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
Joseph Doherty
2026-10-08 16:53:02 -04:00
parent 41e600e069
commit 2aae3c094f
6 changed files with 332 additions and 5 deletions
@@ -45,7 +45,7 @@ def seed_buffer(buf: bytearray, seeds: list[dict]) -> None:
"""Poke seed values into the area buffer at declared byte offsets.
Each seed is {"offset": int, "type": str, "value": int|float|bool|str}
where type ∈ {u8, i8, u16, i16, u32, i32, f32, bool, ascii}. Endianness is
where type ∈ {u8, i8, u16, i16, u32, i32, f32, bool, ascii, hex}. Endianness is
big-endian (Siemens wire format).
"""
for seed in seeds:
@@ -73,6 +73,11 @@ def seed_buffer(buf: bytearray, seeds: list[dict]) -> None:
buf[off] |= (1 << bit)
else:
buf[off] &= ~(1 << bit) & 0xFF
elif t == "hex":
# Raw bytes, big-endian wire order as written. Used for the multi-byte S7 types the
# scalar seeds cannot express (WSTRING, DTL, ...): {"type": "hex", "value": "07e8030f..."}.
raw = bytes.fromhex(str(v).replace(" ", ""))
buf[off:off + len(raw)] = raw
elif t == "ascii":
# Siemens STRING type: byte 0 = max length, byte 1 = current length,
# bytes 2+ = payload. Seeds supply the payload text; we fill max/cur.