feat(rawcli): live relevance hint — per-transponder memory map
Surfaces what the input *means* on the identified tag, in a bottom-bar hint that updates as you type (the point, over aggressive autocomplete): - memory.py: page_role(transponder, page) maps a page/block to its role on the specific IC — UID, Capability Container, user memory, dynamic lock, CFG0/AUTH0, CFG1/ACCESS, PWD, PACK. Layouts mirror the models' page attributes (NTAG210/212/213/215/216, Ultralight EV1); a test guards against drift. - input_hint(session, text): the command's purpose, and — once a page argument is typed (even partial, hex or decimal) — where that page lives. e.g. "READ(4)" -> user memory, "READ(0x2B" -> PWD, "WRITE(0x29" -> CFG0/AUTH0. - app: wired as the prompt's bottom_toolbar. 11 new tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -399,6 +399,50 @@ class TestCompleter:
|
||||
assert any(c.text == "GET_VERSION(" for c in cs)
|
||||
|
||||
|
||||
class TestMemoryHint:
|
||||
def _sess(self, tp="NTAG213"):
|
||||
s = RawSession()
|
||||
s.protocol, s.transponder = "hf14a", tp
|
||||
return s
|
||||
|
||||
def test_page_role(self):
|
||||
from pm3py.cli.rawcli.memory import page_role
|
||||
assert page_role("NTAG213", 0) == "UID / serial number"
|
||||
assert page_role("NTAG213", 3) == "Capability Container (CC)"
|
||||
assert page_role("NTAG213", 4) == "user memory"
|
||||
assert "AUTH0" in page_role("NTAG213", 0x29) # CFG0
|
||||
assert page_role("NTAG213", 0x2A).startswith("CFG1")
|
||||
assert "PWD" in page_role("NTAG213", 0x2B)
|
||||
assert page_role("NTAG216", 0x04) == "user memory" # different IC, different pages
|
||||
assert "AUTH0" in page_role("NTAG216", 0xE3)
|
||||
|
||||
def test_hint_command_and_page_location(self):
|
||||
from pm3py.cli.rawcli.memory import input_hint
|
||||
s = self._sess()
|
||||
assert "user memory" in input_hint(s, "READ(4)")
|
||||
assert "PWD" in input_hint(s, "READ(0x2B") # partial input + hex arg
|
||||
assert "Capability Container" in input_hint(s, "WRITE(3,")
|
||||
|
||||
def test_hint_command_only(self):
|
||||
from pm3py.cli.rawcli.memory import input_hint
|
||||
s = self._sess()
|
||||
assert input_hint(s, "GET_VERSION").startswith("GET_VERSION()")
|
||||
assert input_hint(s, "") is None
|
||||
|
||||
def test_hint_needs_transponder(self):
|
||||
from pm3py.cli.rawcli.memory import input_hint
|
||||
assert input_hint(RawSession(), "READ(4)") is None
|
||||
|
||||
def test_layouts_match_models(self):
|
||||
from pm3py.cli.rawcli.memory import _LAYOUTS
|
||||
from pm3py.sim import NTAG210, NTAG212, NTAG213, NTAG215, NTAG216
|
||||
for cls, name in [(NTAG210, "NTAG210"), (NTAG212, "NTAG212"), (NTAG213, "NTAG213"),
|
||||
(NTAG215, "NTAG215"), (NTAG216, "NTAG216")]:
|
||||
L = _LAYOUTS[name]
|
||||
assert (L["cfg0"], L["cfg1"], L["pwd"], L["pack"]) == \
|
||||
(cls._cfg0_page, cls._cfg1_page, cls._pwd_page, cls._pack_page)
|
||||
|
||||
|
||||
class TestKeyBindings:
|
||||
def test_install_does_not_raise(self):
|
||||
# regression: "c-/" is not a valid prompt_toolkit key and used to crash launch
|
||||
|
||||
Reference in New Issue
Block a user