Files
proxmark3/tools/ePassport/tests/test_logpane.py
T
Paul KilarandClaude Opus 5 bd34414c6d ePassport: fix the FILES and LOG panes going blank
Clicking a file that holds a picture - EF_DG2, EF_DG7 - showed nothing at
all: no image, no hex dump, and no error either.

Both panes drew their text into a single Kivy Label, and a Label is one
OpenGL texture, capped at commonly 16384px. A monospace line here is 13px,
so past roughly 1260 lines the texture fails to be created and the pane
draws nothing. A DG2 portrait is 15-25kB, which is 940-1560 dump lines at
16 bytes a row and four times that in a narrow pane, where the dump falls
back to 4 bytes a row. The LOG pane holds 4000 lines, so it blanked as
well once a dump got talkative. The 64kB cap already in the hex view
guarded the wrong bound: it was sized for how long a Label takes to lay
out, not for what the GPU will hold.

Split both over several Labels. split_blocks() chunks at 512 rows, and the
log at 256 because its lines wrap and so cover more rows than they hold.
The log reuses its Labels and only assigns the ones whose text changed, so
streaming output still re-renders just the tail.

The FILES tab now also shows the picture above the dump for the files that
carry one, which is what you actually want to see for a DG2. The PNG is
already decoded at load time for the data page, so image_for() only hands
over what is there.

Behaviour change: a file carrying an image shows it above the hex dump,
with the dump still underneath. Nothing is truncated that was not before.

Testing: 270 passed, 2 skipped (was 265). Checked on screen against a
generated sample - EF_DG2 shows the portrait, EF_DG7 the signature, EF_SOD
the dump at full height, and the LOG tab renders a full 4000-line buffer
as 16 Labels, tallest texture 3328px against the 16384px maximum. black
clean. Python only, so no client or firmware build matrix applies.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 10:45:57 -04:00

36 lines
1.1 KiB
Python

"""The pm3 log pane.
Long text has to be split across several Labels: a Label is drawn into one
texture, and OpenGL caps texture size at commonly 16384px. A log line is
about 13px, so the pane went blank somewhere past 1260 lines - and it holds
4000, so a talkative dump lost its output entirely.
"""
from __future__ import annotations
from epassport.ui.widgets import textblocks
def test_a_long_log_is_split_into_blocks_a_texture_can_hold() -> None:
rows = [f"[+] line {i}" for i in range(4000)]
blocks = textblocks.split_blocks(rows)
assert len(blocks) > 1
assert all(b.count("\n") + 1 <= textblocks.ROWS_PER_BLOCK for b in blocks)
def test_blocks_join_back_into_the_whole_log() -> None:
rows = [f"line {i}" for i in range(1500)]
assert "\n".join(textblocks.split_blocks(rows)) == "\n".join(rows)
def test_a_short_log_stays_a_single_block() -> None:
assert textblocks.split_blocks(["one", "two"]) == ["one\ntwo"]
def test_no_lines_is_no_blocks() -> None:
assert textblocks.split_blocks([]) == []
def test_rows_per_block_leaves_headroom_under_the_texture_limit() -> None:
assert textblocks.ROWS_PER_BLOCK * 13 <= 16384 / 2