summaryrefslogtreecommitdiff
path: root/test/fs.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/fs.py')
-rw-r--r--test/fs.py90
1 files changed, 90 insertions, 0 deletions
diff --git a/test/fs.py b/test/fs.py
index 2782407d..282cca8b 100644
--- a/test/fs.py
+++ b/test/fs.py
@@ -479,6 +479,22 @@ def run_file(binary):
assert run(client, term, b'fi\n') == b'error not run\n' # a syntax error runs nothing
assert run(client, term, b"echo 'open\n") == b'error not run\n' # nor does an open quote
assert run(client, term, b'true\n') == b'exit 0\n' # ...and the shell is clear after
+ # A paging command run through pty/run does not wait in less: the
+ # terminal's PAGER is `pardes -`, and its text is a +Pager pane.
+ if shutil.which('git'):
+ repo = root / 'pagedrepo'
+ repo.mkdir()
+ git = ['git', '-C', str(repo), '-c', 'user.name=p', '-c', 'user.email=p@x']
+ subprocess.run(git + ['init', '-q'], check=True, env=dict(os.environ, HOME=str(root)))
+ (repo / 'f').write_text('x\n')
+ subprocess.run(git + ['add', 'f'], check=True, env=dict(os.environ, HOME=str(root)))
+ subprocess.run(git + ['commit', '-qm', 'paged-commit-subject'], check=True, env=dict(os.environ, HOME=str(root)))
+ assert run(client, term, b'git -C pagedrepo log\n').startswith(b'exit 0\n')
+ pager = [r.split()[0].decode() for r in client.read('/index').splitlines() if r.split()[3:4] == [f'{repo}/+Pager'.encode()]] # git -C runs it in the repo
+ assert len(pager) == 1, client.read('/index')
+ assert b'paged-commit-subject' in client.read(f'/pane/{pager[0]}/body')
+ assert b'\x1b' not in client.read(f'/pane/{pager[0]}/body')
+ client.remove(f'/pane/{pager[0]}')
# A pty is not given one row (it loses the prompt's input mark,
# and the shell would read busy for ever): refused, and said.
try:
@@ -1306,6 +1322,32 @@ def test(binary, quic=False):
# opened is deleted, as an $EDITOR must; one on a file already open
# waits on that pane; a session that goes away ends it with 1.
with session(binary, root, 'wait') as (client, address):
+ # A command run from a pane's tag gets acme's $winid, that pane;
+ # one from the workspace's tag, none.
+ def command_body(node, line):
+ client.write(node, line)
+ serial = int(client.read(node).split()[-1])
+ deadline = time.monotonic() + 10
+ while True:
+ log = client.read('/log').decode()
+ ran = log.rfind(f'\nrun {serial} ')
+ if ran >= 0 and f'\nexit {serial} ' in log[ran:]:
+ body = client.read(f'/pane/{serial}/body').decode().split('% echo winid')[-1]
+ client.remove(f'/pane/{serial}')
+ return body
+ assert time.monotonic() < deadline, log[-400:]
+ time.sleep(.05)
+ first_pane = min(int(row.split()[0]) for row in client.read('/index').splitlines())
+ assert f'winid={first_pane}\n' in command_body(f'/pane/{first_pane}/tagexec', b'echo winid=$winid\n')
+ assert 'winid=\n' in command_body('/tagexec', b'echo winid=$winid\n')
+ # A second --detach of a name a live session holds: said, exit 1,
+ # no Zig error trace.
+ second_env = {k: v for k, v in os.environ.items() if not k.startswith('PARDES_')}
+ second_env.update(HOME=str(root), XDG_RUNTIME_DIR=str(root))
+ second = subprocess.run([binary, '--detach=wait'], cwd=root, env=second_env,
+ stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, timeout=20)
+ assert second.returncode == 1, second
+ assert second.stderr == b'pardes: a session named wait is already running\n', second.stderr
status = dict(line.split(maxsplit=1) for line in client.read('/status').decode().splitlines())
env = {k: v for k, v in os.environ.items() if k != 'PARDES_FORWARD_LOOK'}
env.update(PARDES_9P=str(address), PARDES_PANE='1', PARDES_PID=status['pid'])
@@ -1395,6 +1437,30 @@ def test(binary, quic=False):
# A pane address the session has not is refused in words, exit
# 1, no pane made for a file of that name; one it has is looked
# at. A name with a newline is said in words, not an error name.
+ # `pardes -` (a terminal's PAGER): stdin, its escapes stripped, in a
+ # +Pager pane of the session, clean, and back at once.
+ fed = subprocess.run([binary, '-'], cwd=root, env=env, input=b'\x1b[1mbold\x1b[0m text\n',
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=10)
+ assert fed.returncode == 0, fed.stderr
+ made_now, = serials() - before
+ assert client.read(f'/pane/{made_now}/name') == f'{root}/+Pager\n'.encode()
+ assert client.read(f'/pane/{made_now}/body') == b'bold text\n'
+ row = [r for r in client.read('/index').splitlines() if r.split()[0] == str(made_now).encode()][0]
+ assert row.split()[2] == b'0', row # clean: nothing to ask at Exit
+ client.remove(f'/pane/{made_now}')
+ # A new name in a directory there but not writable: refused now,
+ # not a pane that only fails at Save.
+ shut = root / 'shut-dir'
+ shut.mkdir()
+ shut.chmod(0o500)
+ try:
+ refused = subprocess.run([binary, 'shut-dir/new.txt'], cwd=root, env=env,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=10)
+ assert refused.returncode == 1, refused
+ assert b'may not be read or written' in refused.stderr, refused.stderr
+ assert serials() == before, (serials(), before)
+ finally:
+ shut.chmod(0o755)
for word, said in (('@p999:1', b'pardes: @p999:1: this session has no such pane'),
('two\nlines.txt', b'a file name is one line')):
refused = subprocess.run([binary, word], cwd=root, env=env,
@@ -1411,6 +1477,30 @@ def test(binary, quic=False):
assert orphan.poll() is None
assert orphan.wait(timeout=5) == 1
+ # `pardes -` outside a session: an editor whose first pane is a
+ # +Pager of stdin, as `vim -`; here a detached one, to read it.
+ outside_env = {k: v for k, v in os.environ.items() if not k.startswith('PARDES_')}
+ outside_env.update(HOME=str(root), XDG_RUNTIME_DIR=str(root), PARDES_NOTIME='1')
+ boot = subprocess.Popen([binary, '--detach=stdinboot', '-'], cwd=root, env=outside_env,
+ stdin=subprocess.PIPE, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE,
+ start_new_session=True)
+ try:
+ boot.stdin.write(b'\x1b[32mfrom stdin\x1b[m\nsecond\n')
+ boot.stdin.close()
+ sock = root / 'pardes-9p-stdinboot.sock'
+ deadline = time.monotonic() + 10
+ while not sock.exists():
+ assert boot.poll() is None, boot.stderr.read()
+ assert time.monotonic() < deadline, 'the stdin boot never listened'
+ time.sleep(.05)
+ with Client(str(sock)) as booted:
+ first = booted.read('/index').split(b'\n')[0].split()
+ assert first[3] == f'{root}/+Pager'.encode(), first
+ assert booted.read(f'/pane/{first[0].decode()}/body') == b'from stdin\nsecond\n'
+ finally:
+ boot.terminate()
+ boot.wait(timeout=10)
+
# Killed with SIGTERM or SIGHUP, a tty editor puts its terminal
# back (main screen, cooked mode) before it dies: a nested one
# killed in a pane leaves that pane usable.