test(rawcli): end-to-end live-session regression for byte-line entry + completion
Drive the real PromptSession that run() builds (real key bindings + RawCompleter + complete_while_typing) via a prompt_toolkit pipe input simulating TTY keystrokes, so the actual rawcli input stack is exercised, not just the handler in isolation. Asserts every input path yields the correct accepted line (hex byte line, binary via toggle, mixed hex/binary, function call, command name) and that the completer is queried live during binary entry (0 queries before the autocomplete fix, since buf.document= reset complete_state). prompt()'s internal asyncio.run() nulls the current-loop pointer; the helper saves and restores it so the shared-loop `_run` convention in other test files is not poisoned. Full suite stays green (1383). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -931,3 +931,65 @@ class TestKeyBindings:
|
||||
digit[ch].handler(SimpleNamespace(current_buffer=buf, app=app, data=ch))
|
||||
assert buf.text == "00000100"
|
||||
assert len(fired) == 8 # one insert_text per digit (0 with document=)
|
||||
|
||||
|
||||
class TestRawcliLiveSession:
|
||||
"""End-to-end through the REAL PromptSession run() builds (real key bindings + RawCompleter +
|
||||
complete_while_typing), driven by a prompt_toolkit pipe input that simulates TTY keystrokes.
|
||||
Exercises the actual rawcli input stack; no device needed for the input layer."""
|
||||
|
||||
@staticmethod
|
||||
def _run_keys(keys):
|
||||
import asyncio
|
||||
from prompt_toolkit import PromptSession
|
||||
from prompt_toolkit.input import create_pipe_input
|
||||
from prompt_toolkit.output import DummyOutput
|
||||
from prompt_toolkit.key_binding import KeyBindings
|
||||
from pm3py.cli.rawcli.entry import install_key_bindings
|
||||
from pm3py.cli.rawcli.completer import RawCompleter
|
||||
state = RawSession()
|
||||
comp = RawCompleter(state)
|
||||
queried = []
|
||||
_orig = comp.get_completions
|
||||
def _rec(document, event):
|
||||
queried.append(document.text)
|
||||
yield from _orig(document, event)
|
||||
comp.get_completions = _rec
|
||||
kb = KeyBindings()
|
||||
install_key_bindings(kb, state)
|
||||
# PromptSession.prompt() runs asyncio.run() internally, which nulls the current-loop
|
||||
# pointer; save/restore it so the shared-loop `_run` convention in other test files isn't
|
||||
# poisoned (see tests/test_pyws_plugin.py).
|
||||
try:
|
||||
prev_loop = asyncio.get_event_loop()
|
||||
except RuntimeError:
|
||||
prev_loop = None
|
||||
try:
|
||||
with create_pipe_input() as inp:
|
||||
session = PromptSession(key_bindings=kb, completer=comp, complete_while_typing=True,
|
||||
input=inp, output=DummyOutput())
|
||||
inp.send_text(keys + "\r")
|
||||
line = session.prompt("> ")
|
||||
finally:
|
||||
if prev_loop is not None and not prev_loop.is_closed():
|
||||
asyncio.set_event_loop(prev_loop)
|
||||
return line, queried
|
||||
|
||||
def test_accepted_line_across_input_paths(self):
|
||||
# the change touched the digit handler; confirm every input path still yields the right line
|
||||
toggle = "\x14" # Ctrl-t entry-mode toggle
|
||||
for keys, expect in [("3004", "30 04"),
|
||||
(toggle + "00000100", "00000100"),
|
||||
("30" + toggle + "00000100", "30 00000100"),
|
||||
("read(4)", "read(4)"),
|
||||
("identify", "identify")]:
|
||||
line, _ = self._run_keys(keys)
|
||||
assert line == expect, f"{keys!r} -> {line!r} != {expect!r}"
|
||||
|
||||
def test_live_completion_fires_during_binary_entry(self):
|
||||
# the fix, in the real session: the completer is queried with the byte-line text while
|
||||
# typing binary (0 queries before the fix, since buf.document= reset complete_state)
|
||||
line, queried = self._run_keys("\x14" + "00000100")
|
||||
byte_q = [q for q in queried if q and q.replace(" ", "").strip("01") == ""]
|
||||
assert line == "00000100"
|
||||
assert byte_q, "completer never queried for byte-line text — live menu not firing"
|
||||
|
||||
Reference in New Issue
Block a user