Files
vt1200/harness/badapple/tests/test_rdebug_load.py
T
arti eabc3051be feat(badapple): the demo as a tool -- rdebug delivery, clip builder, one command
A new folder so the demo can be reproduced instead of re-derived: the delivery
and the clip packing were living in throwaway scripts under /tmp, and the only
written route to a real clip was an ffmpeg recipe that packs MSB first -- the
order that mirrors every eight pixels on a display.

  harness/badapple/rdebug_load.py    image -> terminal RAM over the firmware's
                                     own remote-debug service (TCP 771), then
                                     jump to the entry from vidstream.env
  harness/badapple/clip_from_video.py video -> LSB-first 1-bpp frames for
                                     make_tiles.py --clip
  harness/badapple/demo.sh           ICMP gate, load, send; one command
  harness/badapple/README.md         setup, run in MAME, run on real hardware,
                                     what success looks like, failure modes

The loader records the two protocol facts that cost time to find: a 512-byte
poke chunk (1024 is mis-parsed as a following opcode: "Invalid command
0xA5A5A5A5"), and that nothing can be probed after the jump, so the image is
read back BEFORE jumping and the run is observed from the machine afterwards.

Tests cover what a wrong assumption would silently corrupt -- chunk arithmetic,
the linkage the entry point is read from, and pixel 0 landing on bit 0 -- and
the tool was exercised end to end against MAME: demo.sh loaded the payload and
the terminal reported DICT_BYTES=32768, DICT_BAD=0, RX_OK=28, TILES_DROP=0
while the sender saw frames_rx=129, drops=0.

153 tests pass (7 new).
2026-10-31 20:20:35 +02:00

77 lines
2.8 KiB
Python

"""Tests for the rdebug loader and the clip builder.
The pieces that touch a live terminal cannot be tested here; what is tested is
everything that decides *what* gets written where, because those are the parts a
wrong assumption silently corrupts: the chunking arithmetic, the linkage the
entry point is read from, and the 1-bpp packing the terminal actually reads.
"""
import struct
import pytest
from harness.badapple import clip_from_video
from harness.badapple import rdebug_load
# --- chunking -------------------------------------------------------------
def test_chunks_are_transfer_sized_and_cover_the_image_once():
data = bytes(range(200)) * 23 # 4,600 B: not a multiple of 512
parts = rdebug_load.chunks(data, 512)
assert [len(p) for p in parts] == [512] * 8 + [504]
assert b"".join(parts) == data
def test_chunks_refuse_a_size_the_firmware_cannot_take():
# 1024 is rejected by the firmware: it reads the body's first word as the
# next opcode ("Invalid command 0xA5A5A5A5" on a 0xA5-filled chunk).
with pytest.raises(ValueError):
rdebug_load.chunks(b"x", 1024)
with pytest.raises(ValueError):
rdebug_load.chunks(b"x", 0)
def test_addresses_advance_by_the_chunk_length_in_bits():
base = 0x018C0000
assert rdebug_load.chunk_addr(base, 0) == base
assert rdebug_load.chunk_addr(base, 1) == base + 512 * 8
# --- linkage --------------------------------------------------------------
def test_env_file_gives_the_entry_and_the_pool_size(tmp_path):
env = tmp_path / "vidstream.env"
env.write_text("POOL_BYTES=249856\nSTATIC_PTR=0x01C00080\n"
"ENTRY_PTR=0x018D0270\n")
got = rdebug_load.read_env(env)
assert got["ENTRY_PTR"] == 0x018D0270
assert got["POOL_BYTES"] == 249856
def test_missing_env_file_says_so_instead_of_guessing(tmp_path, capsys):
rc = rdebug_load.main(["--image", "x.bin", "--env", str(tmp_path / "no.env")])
assert rc == 2
err = capsys.readouterr().err
assert "no build environment" in err and "build-stream.sh" in err
# --- the clip format ------------------------------------------------------
def test_packed_rows_put_pixel_zero_on_bit_zero_of_byte_zero():
"""The terminal reads bit 0 of a byte as the leftmost pixel.
Same rule the payload's encoder uses (`vidsrc.Rows.pack_row`), and the one
an MSB-first packer gets wrong in a way that only shows on a display.
"""
pixels = [[0] * 16]
pixels[0][0] = 1 # leftmost pixel of the row
pixels[0][15] = 1 # last pixel of the second byte
row = clip_from_video.pack_row(pixels[0])
assert len(row) == 2
assert row[0] == 0x01
assert row[1] == 0x80
def test_pack_row_rejects_a_short_row():
with pytest.raises(ValueError):
clip_from_video.pack_row([0] * 15)