From 0d6034702a21a44097a54d57c95ae86201decec9 Mon Sep 17 00:00:00 2001 From: Christian Werner Date: Sat, 20 Jun 2026 18:19:47 +0200 Subject: [PATCH] test(iecpoc): add plain-mode tests for TraceFormatter Covers the plain property, per-record-type output (printable chars, CR/LF newlines, LISTEN/UNLISTEN dividers, silenced events and other commands), and a full-session integration check. Generated by Clanker --- tests/test_device.py | 93 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/tests/test_device.py b/tests/test_device.py index 2a47ed4..545da27 100644 --- a/tests/test_device.py +++ b/tests/test_device.py @@ -16,7 +16,11 @@ from . import fixtures def _trace(records, my_address=4, raw=False): - return list(TraceFormatter(my_address=my_address, raw=raw).format_stream(records)) + return list(TraceFormatter(my_address=my_address, raw=raw, debug=True).format_stream(records)) + + +def _plain(records, my_address=4): + return list(TraceFormatter(my_address=my_address).format_stream(records)) # --- wire-format round trip ------------------------------------------------- @@ -101,3 +105,90 @@ def test_raw_mode_is_hex_only(): assert trace[0] == "24" # data bytes present as hex assert "48" in trace # 'H' + + +# --- plain mode ------------------------------------------------------------- +def _make_record(kind, value, flags=0): + from iecpoc.device import IecRecord + return IecRecord(kind, value, flags, 0) + + +def test_plain_property(): + assert TraceFormatter(debug=False).plain is True + assert TraceFormatter(debug=True).plain is False + assert TraceFormatter(raw=True).plain is False + + +def test_plain_listen_divider(): + rec = _make_record(device.KIND_COMMAND, 0x24, device.FLAG_ADDRESSED) # LISTEN 4 + out = _plain([rec]) + assert len(out) == 1 + assert "LISTEN 4" in out[0] + + +def test_plain_unlisten_divider(): + rec = _make_record(device.KIND_COMMAND, 0x3F) # UNLISTEN + out = _plain([rec]) + assert len(out) == 1 + assert "UNLISTEN" in out[0] + + +def test_plain_data_printable(): + rec = _make_record(device.KIND_DATA, 0x48, device.FLAG_ADDRESSED) # 'H' + assert _plain([rec]) == ["H"] + + +def test_plain_data_cr_yields_newline(): + rec = _make_record(device.KIND_DATA, 0x0D, device.FLAG_ADDRESSED) + assert _plain([rec]) == ["\n"] + + +def test_plain_data_lf_yields_newline(): + rec = _make_record(device.KIND_DATA, 0x0A, device.FLAG_ADDRESSED) + assert _plain([rec]) == ["\n"] + + +def test_plain_data_shift_cr_yields_newline(): + rec = _make_record(device.KIND_DATA, 0x8D, device.FLAG_ADDRESSED) + assert _plain([rec]) == ["\n"] + + +def test_plain_events_are_silent(): + recs = [ + _make_record(device.KIND_EVENT, device.EV_IDLE), + _make_record(device.KIND_EVENT, device.EV_ATN_ASSERTED), + _make_record(device.KIND_EVENT, device.EV_ATN_RELEASED), + ] + assert _plain(recs) == [] + + +def test_plain_non_listen_commands_silent(): + recs = [ + _make_record(device.KIND_COMMAND, 0xF0), # OPEN SA=0 + _make_record(device.KIND_COMMAND, 0xE0), # CLOSE SA=0 + _make_record(device.KIND_COMMAND, 0x60), # SECOND/DATA SA=0 + _make_record(device.KIND_COMMAND, 0x48), # TALK 8 + _make_record(device.KIND_COMMAND, 0x5F), # UNTALK + ] + assert _plain(recs) == [] + + +def test_plain_graphic_bytes_silent(): + rec = _make_record(device.KIND_DATA, 0x70, device.FLAG_ADDRESSED) # graphic range + assert _plain([rec]) == [] + + +def test_plain_control_bytes_silent(): + rec = _make_record(device.KIND_DATA, 0x12, device.FLAG_ADDRESSED) # RVS-ON + assert _plain([rec]) == [] + + +def test_plain_full_session(): + out = _plain(fixtures.build_session()) + joined = "".join(out) + assert "HELLO WORLD" in joined + assert "LINE TWO" in joined + assert "LISTEN 4" in joined + assert "UNLISTEN" in joined + # each PRINT# record ends with CR → two newlines from data, plus divider newlines + assert joined.count("\n") >= 2