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

288 lines
8.1 KiB
Python

"""Tests for Rich rendering helpers used by the interactive shell."""
from __future__ import annotations
import io
import re
import threading
import pytest
from rich.console import Console
from surfaces.interactive_shell.runtime.core.state import SpinnerState
from surfaces.interactive_shell.ui.components.rendering import (
_repl_write_buffer,
print_repl_json,
refresh_welcome_poster,
repl_print,
repl_render_launch_poster,
repl_table,
)
from surfaces.interactive_shell.ui.streaming.console import StreamingConsole
from surfaces.interactive_shell.ui.tables import (
render_integrations_table,
render_mcp_table,
)
def test_repl_table_minimal_box() -> None:
t = repl_table(title="T")
assert t.title == "T"
def test_print_repl_json_tty_uses_single_buffered_write(monkeypatch: pytest.MonkeyPatch) -> None:
class _FakeStdout:
def __init__(self) -> None:
self.writes: list[str] = []
def write(self, text: str) -> int:
self.writes.append(text)
return len(text)
def flush(self) -> None:
return None
def isatty(self) -> bool:
return True
fake_stdout = _FakeStdout()
monkeypatch.setattr("sys.stdout", fake_stdout)
console = Console(file=fake_stdout, force_terminal=True, width=80)
print_repl_json(console, '{"ok": true}')
assert len(fake_stdout.writes) == 1
rendered = re.sub(r"\x1b\[[0-9;]*m", "", fake_stdout.writes[0])
assert rendered.startswith("\r\n")
assert '"ok": true' in rendered
def test_render_integrations_table_empty_shows_hint() -> None:
buf = io.StringIO()
console = Console(file=buf, force_terminal=False)
render_integrations_table(console, [])
assert "opensre onboard" in buf.getvalue()
def test_repl_print_resets_before_each_line(monkeypatch) -> None:
resets: list[bool] = []
monkeypatch.setattr(
"surfaces.interactive_shell.ui.components.choice_menu.prepare_repl_output_line",
lambda: resets.append(True),
)
buf = io.StringIO()
console = Console(file=buf, force_terminal=False, width=80)
repl_print(console, "line one")
repl_print(console, "line two")
assert len(resets) == 2
def test_repl_print_does_not_double_prepare_with_streaming_console(monkeypatch) -> None:
resets: list[bool] = []
monkeypatch.setattr(
"surfaces.interactive_shell.ui.components.choice_menu.prepare_repl_output_line",
lambda: resets.append(True),
)
console = StreamingConsole(
SpinnerState(),
threading.Event(),
file=io.StringIO(),
force_terminal=False,
width=80,
)
repl_print(console, "line")
assert len(resets) == 1
def test_repl_print_streaming_console_prepares_tty_once_when_interactive(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeStdout:
def __init__(self) -> None:
self.writes: list[str] = []
def write(self, text: str) -> int:
self.writes.append(text)
return len(text)
def flush(self) -> None:
return None
def isatty(self) -> bool:
return True
fake_stdout = _FakeStdout()
monkeypatch.setattr("sys.stdout", fake_stdout)
monkeypatch.setattr(
"surfaces.interactive_shell.ui.components.choice_menu.repl_tty_interactive",
lambda: True,
)
console = StreamingConsole(
SpinnerState(),
threading.Event(),
file=io.StringIO(),
force_terminal=False,
width=80,
)
repl_print(console, "line")
assert fake_stdout.writes == ["\r\n", "\r"]
def test_repl_render_launch_poster_uses_crlf_on_tty(monkeypatch: pytest.MonkeyPatch) -> None:
class _FakeStdout:
def __init__(self) -> None:
self.writes: list[str] = []
def write(self, text: str) -> int:
self.writes.append(text)
return len(text)
def flush(self) -> None:
return None
def isatty(self) -> bool:
return True
fake_stdout = _FakeStdout()
monkeypatch.setattr("sys.stdout", fake_stdout)
from platform.terminal.theme import set_active_theme
set_active_theme("blue")
console = Console(
file=fake_stdout,
force_terminal=True,
highlight=False,
color_system="truecolor",
width=120,
)
repl_render_launch_poster(console, theme_notice="blue")
written = "".join(fake_stdout.writes)
assert "theme set:" in written
assert "blue" in written
assert "38;2;168;212;255" in written
assert "185;237;175" not in written
assert "opensre" in written
assert "Welcome back" in written
assert "\r\n" in written
# REPL path must not emit bare \\n (causes double-spaced splash under patch_stdout).
assert "\r" not in written.replace("\r\n", "")
def test_repl_write_buffer_strips_only_escaped_cpr_sequences(
monkeypatch: pytest.MonkeyPatch,
) -> None:
class _FakeStdout:
def __init__(self) -> None:
self.writes: list[str] = []
def write(self, text: str) -> int:
self.writes.append(text)
return len(text)
def flush(self) -> None:
return None
fake_stdout = _FakeStdout()
monkeypatch.setattr("sys.stdout", fake_stdout)
_repl_write_buffer("\x1b[1;1Rtheme set: pink 12;5R\r\n")
written = "".join(fake_stdout.writes)
assert "theme set: pink" in written
assert "12;5R" in written
assert "\x1b[1;1R" not in written
def test_refresh_welcome_poster_drains_cpr_after_clear(monkeypatch: pytest.MonkeyPatch) -> None:
drains: list[str] = []
monkeypatch.setattr(
"surfaces.interactive_shell.ui.components.rendering.repl_clear_screen",
lambda: drains.append("clear"),
)
monkeypatch.setattr(
"surfaces.interactive_shell.ui.components.cpr_stdin.drain_stale_cpr_bytes",
lambda: drains.append("drain"),
)
monkeypatch.setattr(
"surfaces.interactive_shell.ui.components.rendering.repl_render_launch_poster",
lambda *_args, **_kwargs: drains.append("render"),
)
console = Console(file=io.StringIO(), force_terminal=False)
refresh_welcome_poster(console)
assert drains == ["clear", "drain", "render"]
def test_render_integrations_table_renders_content(
capsys: pytest.CaptureFixture[str],
) -> None:
"""print_repl_table on a non-TTY console writes via console.print to stdout.
The cursor-reset (prepare_repl_output_line) is no longer called from the
table rendering path; on a real TTY the blank line and \\r\\n normalisation
are folded into a single sys.stdout.write call in print_repl_table.
"""
console = Console(force_terminal=False, width=80)
render_integrations_table(
console,
[
{
"service": "grafana",
"source": "local store",
"status": "passed",
"detail": "Connected to https://example.grafana.net",
}
],
)
assert "grafana" in capsys.readouterr().out
def test_render_integrations_table_sorts_services_and_includes_mcp(
capsys: pytest.CaptureFixture[str],
) -> None:
console = Console(force_terminal=False, width=80)
render_integrations_table(
console,
[
{"service": "sentry", "source": "-", "status": "missing", "detail": "missing"},
{"service": "github", "source": "-", "status": "missing", "detail": "missing"},
{"service": "datadog", "source": "env", "status": "passed", "detail": "ok"},
],
)
output = capsys.readouterr().out
assert output.index("datadog") < output.index("github") < output.index("sentry")
assert "github" in output
def test_render_mcp_table_renders_content(
capsys: pytest.CaptureFixture[str],
) -> None:
console = Console(force_terminal=False, width=80)
render_mcp_table(
console,
[
{
"service": "github",
"source": "local store",
"status": "configured",
"detail": "Connected",
}
],
)
assert "github" in capsys.readouterr().out