from __future__ import annotations from pyro_mcp.workspace_shell_output import render_plain_shell_output def test_render_plain_shell_output_strips_ansi_osc_and_controls() -> None: raw = "\x1b]0;title\x07\x1b[31mred\x1b[0m\t\x01done" assert render_plain_shell_output(raw) == "red\tdone" def test_render_plain_shell_output_handles_carriage_return_and_backspace() -> None: raw = "hello\r\x1b[2Kbye\nabc\b\bZ" assert render_plain_shell_output(raw) == "bye\naZ" def test_render_plain_shell_output_preserves_trailing_newlines() -> None: assert render_plain_shell_output("line one\n") == "line one\n" assert render_plain_shell_output("\n") == "\n" def test_render_plain_shell_output_handles_line_clear_modes_and_overwrite() -> None: assert render_plain_shell_output("abcde\rab\x1b[1KZ") == " Zde" assert render_plain_shell_output("hello\x1b[2Kx") == "x" def test_render_plain_shell_output_handles_full_screen_clear() -> None: assert render_plain_shell_output("one\ntwo\x1b[2Jz") == "z" assert render_plain_shell_output("one\ntwo\x1b[3Jz") == "z" def test_render_plain_shell_output_ignores_incomplete_and_non_csi_escape_sequences() -> None: assert render_plain_shell_output("\x1b") == "" assert render_plain_shell_output("\x1b[") == "" assert render_plain_shell_output("\x1b]title\x1b\\ok") == "ok" assert render_plain_shell_output("a\x1bOPb") == "ab" assert render_plain_shell_output("a\x1bXb") == "ab"