2026-08-24 22:23:57 +02:00
|
|
|
import os
|
|
|
|
|
import pty
|
|
|
|
|
import select
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
from tamq.terminal import (
|
|
|
|
|
TerminalOutputError,
|
2026-08-25 19:26:27 +02:00
|
|
|
format_delivery,
|
2026-08-24 22:23:57 +02:00
|
|
|
terminal_frame,
|
|
|
|
|
write_terminal_output,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2026-08-25 19:26:27 +02:00
|
|
|
def test_delivery_format_escapes_controls_and_marks_operator_origin():
|
|
|
|
|
assert format_delivery("repo-a", "first\nsecond\x1b[31m", "operator_input") == (
|
2026-08-25 23:22:39 +02:00
|
|
|
"From:repo-a/o: first\nFrom:repo-a/o: second\\x1b[31m"
|
2026-08-24 22:23:57 +02:00
|
|
|
)
|
2026-08-25 19:26:27 +02:00
|
|
|
assert format_delivery("repo-a", "worker", "worker_output") == (
|
|
|
|
|
"From:repo-a: worker"
|
2026-08-24 23:41:09 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2026-08-24 23:03:30 +02:00
|
|
|
def test_terminal_frame_scrolls_only_rows_above_the_cursor():
|
|
|
|
|
assert terminal_frame(
|
2026-08-25 19:26:27 +02:00
|
|
|
"repo-a", "hello", "operator_input", cursor_y=8, pane_height=24
|
2026-08-24 23:03:30 +02:00
|
|
|
) == (
|
|
|
|
|
"\x1b7\x1b[1;8r\x1b[8;1H"
|
2026-08-25 19:26:27 +02:00
|
|
|
"\n\rFrom:repo-a/o: hello"
|
2026-08-24 23:03:30 +02:00
|
|
|
"\x1b[r\x1b8"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_terminal_frame_falls_back_when_stable_region_is_not_safe():
|
2026-08-25 19:26:27 +02:00
|
|
|
expected = "\r\nFrom:repo-a: hello\r\n"
|
|
|
|
|
assert terminal_frame("repo-a", "hello", "worker_output", cursor_y=0, pane_height=24) == expected
|
2026-08-24 23:03:30 +02:00
|
|
|
assert terminal_frame(
|
2026-08-25 19:26:27 +02:00
|
|
|
"repo-a", "hello", "worker_output", cursor_y=8, pane_height=24, alternate_on=True
|
2026-08-24 23:03:30 +02:00
|
|
|
) == expected
|
2026-08-24 22:23:57 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_terminal_output_reaches_pty_output_but_not_input():
|
|
|
|
|
master, slave = pty.openpty()
|
|
|
|
|
try:
|
|
|
|
|
tty_path = os.ttyname(slave)
|
2026-08-25 19:26:27 +02:00
|
|
|
write_terminal_output(tty_path, terminal_frame("repo-a", "hello", "worker_output"))
|
2026-08-24 22:23:57 +02:00
|
|
|
|
|
|
|
|
readable, _, _ = select.select([master], [], [], 1)
|
|
|
|
|
assert readable == [master]
|
2026-08-25 19:26:27 +02:00
|
|
|
assert b"From:repo-a: hello" in os.read(master, 4096)
|
2026-08-24 22:23:57 +02:00
|
|
|
readable_input, _, _ = select.select([slave], [], [], 0)
|
|
|
|
|
assert readable_input == []
|
|
|
|
|
finally:
|
|
|
|
|
os.close(master)
|
|
|
|
|
os.close(slave)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_terminal_output_rejects_non_pty_paths(tmp_path):
|
|
|
|
|
target = tmp_path / "ordinary-file"
|
|
|
|
|
target.write_text("untouched", encoding="utf-8")
|
|
|
|
|
with pytest.raises(TerminalOutputError, match="non-PTY"):
|
|
|
|
|
write_terminal_output(target, "message")
|
|
|
|
|
assert target.read_text(encoding="utf-8") == "untouched"
|