Files
wehub-resource-sync 4b6817381b
Benchmark image — build + push to ECR (any adapter) / build + push (push) Waiting to run
CI / quality (ubuntu-latest) (push) Waiting to run
CI / test (tools-runtime) (push) Waiting to run
CI / test (e2e-general) (push) Waiting to run
CI / test (cli-runtime) (push) Waiting to run
CI / test (e2e-provider-and-openclaw) (push) Waiting to run
CI / test (integrations-and-misc) (push) Waiting to run
CI / coverage-report (push) Blocked by required conditions
CI / test-kubernetes (push) Waiting to run
CI / should-run-thorough (push) Waiting to run
CI / test-thorough (cloudwatch-demo) (push) Blocked by required conditions
CI / test-thorough (flink-ecs) (push) Blocked by required conditions
CI / test-thorough (upstream-lambda) (push) Blocked by required conditions
CI / test-thorough (prefect-ecs-fargate) (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Blocked by required conditions
Release / publish-release (push) Blocked by required conditions
Release / publish-main-release (push) Blocked by required conditions
Release / prepare (push) Waiting to run
Release / verify (push) Blocked by required conditions
Release / build-python-dist (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Blocked by required conditions
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Waiting to run
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

123 lines
3.9 KiB
Python

"""Tests for inline raw-terminal choice menu rendering."""
from __future__ import annotations
import io
import re
import sys
from types import SimpleNamespace
from surfaces.interactive_shell.ui.components import choice_menu
_ANSI_RE = re.compile(r"\x1b\[[0-9;:]*[A-Za-z]")
def test_draw_menu_uses_carriage_return_newlines(monkeypatch) -> None:
"""Raw-mode terminals do not translate LF to CRLF for us.
Plain ``\n`` makes each line begin at the previous line's ending column,
which renders the picker as a diagonal staircase. The inline menu should
write explicit ``\r\n`` newlines and reset to column zero for every row.
"""
out = io.StringIO()
monkeypatch.setattr(sys, "stdout", out)
monkeypatch.setattr(choice_menu, "_cols", lambda: 80)
choice_menu._draw_menu(
title="integrations",
crumb="/integrations",
labels=["/integrations list", "/integrations verify"],
index=0,
erase_lines=0,
)
rendered = out.getvalue()
plain = _ANSI_RE.sub("", rendered)
assert "\n" in rendered
assert all(rendered[index - 1] == "\r" for index, char in enumerate(rendered) if char == "\n")
assert "\rintegrations" in plain
assert "\r/integrations" in plain
assert "\r > /integrations list" in plain
def test_erase_menu_block_resets_to_column_zero(monkeypatch) -> None:
out = io.StringIO()
monkeypatch.setattr(sys, "stdout", out)
choice_menu._erase_menu("crumb", ["one", "two"])
rendered = out.getvalue()
assert rendered.startswith("\r\x1b[")
assert "A\r\x1b[J" in rendered
assert rendered.endswith("\r")
def test_reset_tty_column_writes_carriage_return(monkeypatch) -> None:
out = io.StringIO()
monkeypatch.setattr(sys, "stdout", out)
choice_menu.reset_tty_column()
assert out.getvalue() == "\r"
def test_pick_ignores_unmapped_keys(monkeypatch) -> None:
out = io.StringIO()
actions = iter(["ignore", "enter"])
monkeypatch.setattr(sys, "stdout", out)
monkeypatch.setattr(choice_menu, "_cols", lambda: 80)
monkeypatch.setattr(choice_menu, "_read_action", lambda: next(actions))
assert choice_menu._pick(title="test", crumb="", labels=["one"]) == 0
rendered = out.getvalue()
assert rendered.count("test") == 2
assert "A\r\x1b[J" in rendered
def test_read_action_treats_space_as_enter(monkeypatch) -> None:
monkeypatch.setattr(choice_menu.os, "name", "nt")
monkeypatch.setitem(sys.modules, "msvcrt", SimpleNamespace(getch=lambda: b" "))
assert choice_menu._read_action() == "enter"
def test_read_action_treats_right_arrow_as_enter(monkeypatch) -> None:
keys = iter([b"\xe0", b"M"])
monkeypatch.setattr(choice_menu.os, "name", "nt")
monkeypatch.setitem(sys.modules, "msvcrt", SimpleNamespace(getch=lambda: next(keys)))
assert choice_menu._read_action() == "enter"
def test_repl_choose_one_starts_at_initial_value(monkeypatch) -> None:
out = io.StringIO()
actions = iter(["enter"])
monkeypatch.setattr(choice_menu, "repl_tty_interactive", lambda: True)
monkeypatch.setattr(
"surfaces.interactive_shell.ui.components.cpr_stdin.drain_stale_cpr_bytes",
lambda: None,
)
monkeypatch.setattr(sys, "stdout", out)
monkeypatch.setattr(choice_menu, "_cols", lambda: 80)
monkeypatch.setattr(choice_menu, "_read_action", lambda: next(actions))
result = choice_menu.repl_choose_one(
title="theme",
breadcrumb="/theme",
choices=[("green", "green"), ("blue", "blue (current)"), ("pink", "pink")],
initial_value="blue",
)
assert result == "blue"
plain = _ANSI_RE.sub("", out.getvalue())
assert "> blue (current)" in plain
def test_read_action_ignores_left_arrow(monkeypatch) -> None:
keys = iter([b"\xe0", b"K"])
monkeypatch.setattr(choice_menu.os, "name", "nt")
monkeypatch.setitem(sys.modules, "msvcrt", SimpleNamespace(getch=lambda: next(keys)))
assert choice_menu._read_action() == "ignore"