1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
#!/usr/bin/env python3
"""The interactive client's input path, which headless cannot cover.
The encoding matrix (kitty/legacy/mouse/paste, per pane) lives in
tests/test_screen.py, where it runs deterministically through the headless
driver. What is left here is the part that only exists with a real tty: raw
mode, reading stdin, and the prefix key.
"""
import fcntl
import os
import pty
import select
import signal
import struct
import sys
import termios
import time
import uuid
BIN = os.environ.get(
"SLOSH_BIN", os.path.join(os.path.dirname(__file__), "..", "build", "slosh")
)
INNER = ["--", "/bin/sh", "-c", "stty raw -echo; cat -v"]
fails = 0
def check(name, cond, detail=""):
global fails
if not cond:
fails += 1
print(f"{'ok ' if cond else 'FAIL'} {name}{'' if cond else ' <- ' + detail}")
def drain(fd, idle=0.25, limit=2.0):
buf, last, start = b"", time.time(), time.time()
while time.time() - start < limit:
r, _, _ = select.select([fd], [], [], 0.05)
if r:
try:
chunk = os.read(fd, 65536)
except OSError:
break
if not chunk:
break
buf += chunk
last = time.time()
elif time.time() - last > idle:
break
return buf
def main():
session = "test-" + uuid.uuid4().hex[:8]
pid, fd = pty.fork()
if pid == 0:
os.environ["TERM"] = "xterm-ghostty"
os.environ["SLOSH_CONFIG"] = "/nonexistent/slosh.kdl"
os.execv(BIN, [BIN, "-s", session] + INNER)
os._exit(127)
fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack("HHHH", 10, 80, 0, 0))
drain(fd)
os.write(fd, b"\x1b[1;5A")
out = drain(fd).decode("utf-8", "replace")
check(
"a key typed at a real tty reaches the pane", "^[[1;5A" in out, repr(out[-60:])
)
os.write(fd, b"\x01g") # prefix + a key that is bound to nothing
out = drain(fd)
check("prefix + unbound key is swallowed", out == b"", repr(out[-60:]))
os.write(fd, b"\x01\x01") # prefix + prefix = literal
out = drain(fd).decode("utf-8", "replace")
check("C-a C-a sends a literal ^A", "^A" in out, repr(out[-60:]))
os.write(fd, b"\x01q")
drain(fd, idle=0.2, limit=1.0)
try:
os.kill(pid, signal.SIGKILL)
os.waitpid(pid, 0)
except (ProcessLookupError, ChildProcessError):
pass
print(f"\n{'FAILED' if fails else 'all green'} ({fails} failures)")
return 1 if fails else 0
if __name__ == "__main__":
sys.exit(main())
|