2020-08-10 16:54:45 -04:00
|
|
|
"""Tests involving running Xonsh in subproc.
|
|
|
|
This requires Xonsh installed in venv or otherwise available on PATH
|
|
|
|
"""
|
2016-10-13 02:03:30 -04:00
|
|
|
import os
|
2016-10-13 02:45:37 -04:00
|
|
|
import shutil
|
2019-02-06 14:51:52 -05:00
|
|
|
import tempfile
|
2016-10-16 22:20:36 +03:00
|
|
|
import subprocess as sp
|
2016-10-13 02:03:30 -04:00
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
2021-05-28 15:42:37 +03:00
|
|
|
import xonsh
|
2019-02-06 14:51:52 -05:00
|
|
|
from xonsh.lib.os import indir
|
2016-10-13 02:41:53 -04:00
|
|
|
|
2018-08-30 09:18:49 -05:00
|
|
|
from tools import (
|
2020-08-05 13:15:56 +02:00
|
|
|
skip_if_on_msys,
|
2018-08-30 09:18:49 -05:00
|
|
|
skip_if_on_windows,
|
2020-08-05 13:15:56 +02:00
|
|
|
skip_if_on_darwin,
|
2018-08-30 09:18:49 -05:00
|
|
|
ON_WINDOWS,
|
|
|
|
ON_DARWIN,
|
|
|
|
ON_TRAVIS,
|
|
|
|
)
|
2016-10-16 20:30:24 +03:00
|
|
|
|
2016-10-16 21:08:37 +03:00
|
|
|
|
2018-08-30 09:18:49 -05:00
|
|
|
PATH = (
|
2020-08-10 14:53:31 -04:00
|
|
|
os.path.join(os.path.abspath(os.path.dirname(__file__)), "bin")
|
2018-08-30 09:18:49 -05:00
|
|
|
+ os.pathsep
|
|
|
|
+ os.environ["PATH"]
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
skip_if_no_xonsh = pytest.mark.skipif(
|
2020-08-10 14:53:31 -04:00
|
|
|
shutil.which("xonsh") is None, reason="xonsh not on PATH"
|
2019-02-06 14:51:52 -05:00
|
|
|
)
|
|
|
|
skip_if_no_make = pytest.mark.skipif(
|
2020-08-10 14:53:31 -04:00
|
|
|
shutil.which("make") is None, reason="make command not on PATH"
|
2019-02-06 14:51:52 -05:00
|
|
|
)
|
|
|
|
skip_if_no_sleep = pytest.mark.skipif(
|
2020-08-10 14:53:31 -04:00
|
|
|
shutil.which("sleep") is None, reason="sleep command not on PATH"
|
2018-08-30 09:18:49 -05:00
|
|
|
)
|
2017-02-12 11:42:44 -05:00
|
|
|
|
|
|
|
|
2020-08-10 14:53:31 -04:00
|
|
|
def run_xonsh(
|
2021-05-28 15:42:37 +03:00
|
|
|
cmd,
|
|
|
|
stdin=sp.PIPE,
|
|
|
|
stdout=sp.PIPE,
|
|
|
|
stderr=sp.STDOUT,
|
|
|
|
single_command=False,
|
|
|
|
interactive=False,
|
2020-08-10 14:53:31 -04:00
|
|
|
):
|
2016-10-16 21:08:37 +03:00
|
|
|
env = dict(os.environ)
|
2020-08-10 16:54:45 -04:00
|
|
|
env["PATH"] = PATH
|
2020-08-10 01:43:51 -04:00
|
|
|
env["XONSH_DEBUG"] = "0" # was "1"
|
2018-08-30 09:18:49 -05:00
|
|
|
env["XONSH_SHOW_TRACEBACK"] = "1"
|
2018-12-19 17:28:40 -05:00
|
|
|
env["RAISE_SUBPROC_ERROR"] = "0"
|
2018-08-30 09:18:49 -05:00
|
|
|
env["PROMPT"] = ""
|
2020-08-10 14:53:31 -04:00
|
|
|
xonsh = shutil.which("xonsh", path=PATH)
|
2021-05-28 15:42:37 +03:00
|
|
|
args = [xonsh, "--no-rc"]
|
|
|
|
if interactive:
|
|
|
|
args.append("-i")
|
2020-07-28 17:35:16 +02:00
|
|
|
if single_command:
|
2021-05-28 15:42:37 +03:00
|
|
|
args += ["-c", cmd]
|
2020-07-28 17:35:16 +02:00
|
|
|
input = None
|
|
|
|
else:
|
|
|
|
input = cmd
|
|
|
|
|
2018-08-30 09:18:49 -05:00
|
|
|
proc = sp.Popen(
|
2020-07-28 17:35:16 +02:00
|
|
|
args,
|
2018-08-30 09:18:49 -05:00
|
|
|
env=env,
|
|
|
|
stdin=stdin,
|
|
|
|
stdout=stdout,
|
|
|
|
stderr=stderr,
|
|
|
|
universal_newlines=True,
|
|
|
|
)
|
2020-07-28 17:35:16 +02:00
|
|
|
|
2016-10-16 21:08:37 +03:00
|
|
|
try:
|
2020-08-10 16:54:45 -04:00
|
|
|
out, err = proc.communicate(input=input, timeout=20)
|
2016-10-16 22:20:36 +03:00
|
|
|
except sp.TimeoutExpired:
|
2016-10-16 21:08:37 +03:00
|
|
|
proc.kill()
|
|
|
|
raise
|
|
|
|
return out, err, proc.returncode
|
|
|
|
|
2017-02-12 13:11:29 -05:00
|
|
|
|
2020-07-28 17:35:16 +02:00
|
|
|
def check_run_xonsh(cmd, fmt, exp, exp_rtn=0):
|
2017-02-12 13:11:29 -05:00
|
|
|
"""The ``fmt`` parameter is a function
|
|
|
|
that formats the output of cmd, can be None.
|
|
|
|
"""
|
2018-09-13 16:49:09 -04:00
|
|
|
out, err, rtn = run_xonsh(cmd, stderr=sp.PIPE)
|
2017-02-12 13:11:29 -05:00
|
|
|
if callable(fmt):
|
|
|
|
out = fmt(out)
|
|
|
|
if callable(exp):
|
|
|
|
exp = exp()
|
2018-09-13 16:49:09 -04:00
|
|
|
assert out == exp, err
|
2020-07-28 17:35:16 +02:00
|
|
|
assert rtn == exp_rtn, err
|
2017-02-12 13:11:29 -05:00
|
|
|
|
|
|
|
|
2016-10-13 02:03:30 -04:00
|
|
|
#
|
|
|
|
# The following list contains a (stdin, stdout, returncode) tuples
|
|
|
|
#
|
|
|
|
|
|
|
|
ALL_PLATFORMS = [
|
2018-08-30 09:18:49 -05:00
|
|
|
# test calling a function alias
|
|
|
|
(
|
|
|
|
"""
|
2016-10-13 02:03:30 -04:00
|
|
|
def _f():
|
|
|
|
print('hello')
|
|
|
|
|
|
|
|
aliases['f'] = _f
|
|
|
|
f
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"hello\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
# test redirecting a function alias to a file
|
|
|
|
(
|
|
|
|
"""
|
2016-10-13 02:03:30 -04:00
|
|
|
def _f():
|
|
|
|
print('Wow Mom!')
|
|
|
|
|
|
|
|
aliases['f'] = _f
|
|
|
|
f > tttt
|
|
|
|
|
|
|
|
with open('tttt') as tttt:
|
|
|
|
s = tttt.read().strip()
|
|
|
|
print('REDIRECTED OUTPUT: ' + s)
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"REDIRECTED OUTPUT: Wow Mom!\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
# test redirecting a function alias from stderr -> stdout
|
|
|
|
(
|
|
|
|
"""
|
2017-12-07 23:24:06 -05:00
|
|
|
def _f(args, stdin, stdout, stderr):
|
|
|
|
print('The Truth is Out There', file=stderr)
|
|
|
|
|
|
|
|
aliases['f'] = _f
|
|
|
|
f e>o
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"The Truth is Out There\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
# test system exit in function alias
|
|
|
|
(
|
|
|
|
"""
|
2016-10-13 03:20:42 -04:00
|
|
|
import sys
|
|
|
|
def _f():
|
|
|
|
sys.exit(42)
|
|
|
|
|
|
|
|
aliases['f'] = _f
|
|
|
|
print(![f].returncode)
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"42\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
# test uncaptured streaming alias,
|
|
|
|
# order actually printed in is non-deterministic
|
|
|
|
(
|
|
|
|
"""
|
2016-10-13 22:53:06 -04:00
|
|
|
def _test_stream(args, stdin, stdout, stderr):
|
2016-10-24 22:41:01 -04:00
|
|
|
print('hallo on stream', file=stderr)
|
|
|
|
print('hallo on stream', file=stdout)
|
2016-10-13 22:53:06 -04:00
|
|
|
return 1
|
|
|
|
|
|
|
|
aliases['test-stream'] = _test_stream
|
|
|
|
x = ![test-stream]
|
|
|
|
print(x.returncode)
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"hallo on stream\nhallo on stream\n1\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
# test captured streaming alias
|
|
|
|
(
|
|
|
|
"""
|
2016-10-13 22:53:06 -04:00
|
|
|
def _test_stream(args, stdin, stdout, stderr):
|
|
|
|
print('hallo on err', file=stderr)
|
|
|
|
print('hallo on out', file=stdout)
|
|
|
|
return 1
|
|
|
|
|
|
|
|
aliases['test-stream'] = _test_stream
|
|
|
|
x = !(test-stream)
|
|
|
|
print(x.returncode)
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
2021-04-13 20:21:43 +03:00
|
|
|
"1\n",
|
2018-08-30 09:18:49 -05:00
|
|
|
0,
|
|
|
|
),
|
2021-04-12 22:31:45 +03:00
|
|
|
# test captured streaming alias without stderr
|
|
|
|
(
|
|
|
|
"""
|
|
|
|
def _test_stream(args, stdin, stdout, stderr):
|
|
|
|
print('hallo on err', file=stderr)
|
|
|
|
print('hallo on out', file=stdout)
|
|
|
|
return 1
|
|
|
|
|
|
|
|
aliases['test-stream'] = _test_stream
|
2021-04-13 20:21:43 +03:00
|
|
|
with __xonsh__.env.swap(XONSH_SUBPROC_CAPTURED_PRINT_STDERR=True):
|
2021-04-12 22:31:45 +03:00
|
|
|
x = !(test-stream)
|
|
|
|
print(x.returncode)
|
|
|
|
""",
|
2021-04-13 20:21:43 +03:00
|
|
|
"hallo on err\n1\n",
|
2021-04-12 22:31:45 +03:00
|
|
|
0,
|
|
|
|
),
|
2018-08-30 09:18:49 -05:00
|
|
|
# test piping aliases
|
|
|
|
(
|
|
|
|
"""
|
2016-10-16 12:07:39 -04:00
|
|
|
def dummy(args, inn, out, err):
|
|
|
|
out.write('hey!')
|
|
|
|
return 0
|
|
|
|
|
|
|
|
def dummy2(args, inn, out, err):
|
|
|
|
s = inn.read()
|
|
|
|
out.write(s.upper())
|
|
|
|
return 0
|
|
|
|
|
|
|
|
aliases['d'] = dummy
|
|
|
|
aliases['d2'] = dummy2
|
|
|
|
d | d2
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"HEY!",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
# test output larger than most pipe buffers
|
|
|
|
(
|
|
|
|
"""
|
2016-10-18 21:14:08 -04:00
|
|
|
def _g(args, stdin=None):
|
|
|
|
for i in range(1000):
|
|
|
|
print('x' * 100)
|
|
|
|
|
|
|
|
aliases['g'] = _g
|
|
|
|
g
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
(("x" * 100) + "\n") * 1000,
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
# test piping 'real' command
|
|
|
|
(
|
|
|
|
"""
|
2016-10-25 20:55:42 -04:00
|
|
|
with open('tttt', 'w') as fp:
|
|
|
|
fp.write("Wow mom!\\n")
|
|
|
|
|
2020-08-10 14:53:31 -04:00
|
|
|
![python tests/bin/cat tttt | python tests/bin/wc]
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
2020-08-10 01:43:51 -04:00
|
|
|
" 1 2 10 <stdin>\n" if ON_WINDOWS else " 1 2 9 <stdin>\n",
|
2018-08-30 09:18:49 -05:00
|
|
|
0,
|
|
|
|
),
|
|
|
|
# test double piping 'real' command
|
|
|
|
(
|
|
|
|
"""
|
2016-10-26 20:51:28 -04:00
|
|
|
with open('tttt', 'w') as fp:
|
|
|
|
fp.write("Wow mom!\\n")
|
|
|
|
|
2020-08-10 14:53:31 -04:00
|
|
|
![python tests/bin/cat tttt | python tests/bin/wc | python tests/bin/wc]
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
2020-08-10 01:43:51 -04:00
|
|
|
" 1 4 18 <stdin>\n" if ON_WINDOWS else " 1 4 16 <stdin>\n",
|
2018-08-30 09:18:49 -05:00
|
|
|
0,
|
|
|
|
),
|
|
|
|
# test unthreadable alias (which should trigger a ProcPoxy call)
|
|
|
|
(
|
|
|
|
"""
|
2017-02-12 11:01:24 +08:00
|
|
|
from xonsh.tools import unthreadable
|
2017-02-11 14:54:36 -05:00
|
|
|
|
|
|
|
@unthreadable
|
|
|
|
def _f():
|
|
|
|
return 'hello\\n'
|
|
|
|
|
|
|
|
aliases['f'] = _f
|
|
|
|
f
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"hello\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
# test ambiguous globs
|
|
|
|
(
|
|
|
|
"""
|
2017-02-26 21:54:39 -05:00
|
|
|
import os
|
|
|
|
|
|
|
|
def _echo(args):
|
|
|
|
print(' '.join(args))
|
|
|
|
aliases['echo'] = _echo
|
|
|
|
|
|
|
|
files = ['Actually_test.tst', 'Actually.tst', 'Complete_test.tst', 'Complete.tst']
|
|
|
|
|
|
|
|
# touch the file
|
|
|
|
for f in files:
|
|
|
|
with open(f, 'w'):
|
|
|
|
pass
|
|
|
|
|
|
|
|
# echo the files
|
|
|
|
echo *.tst and echo *_test.tst
|
|
|
|
echo *_test.tst
|
|
|
|
echo *_test.tst and echo *.tst
|
|
|
|
|
|
|
|
# remove the files
|
|
|
|
for f in files:
|
|
|
|
os.remove(f)
|
2017-02-27 14:11:39 -05:00
|
|
|
""",
|
2018-08-30 09:18:49 -05:00
|
|
|
"Actually.tst Actually_test.tst Complete.tst Complete_test.tst\n"
|
|
|
|
"Actually_test.tst Complete_test.tst\n"
|
|
|
|
"Actually_test.tst Complete_test.tst\n"
|
|
|
|
"Actually_test.tst Complete_test.tst\n"
|
|
|
|
"Actually.tst Actually_test.tst Complete.tst Complete_test.tst\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
#
|
|
|
|
# test ambiguous line continuations
|
|
|
|
#
|
|
|
|
(
|
|
|
|
"""
|
2017-03-02 22:49:52 -05:00
|
|
|
def _echo(args):
|
|
|
|
print(' '.join(args))
|
|
|
|
aliases['echo'] = _echo
|
|
|
|
|
2020-06-21 15:55:30 +02:00
|
|
|
echo --option1 \\
|
2017-03-02 22:49:52 -05:00
|
|
|
--option2
|
2020-06-21 15:55:30 +02:00
|
|
|
echo missing \\
|
|
|
|
EOL""",
|
|
|
|
"--option1 --option2\nmissing EOL\n",
|
2018-08-30 09:18:49 -05:00
|
|
|
0,
|
|
|
|
),
|
|
|
|
#
|
|
|
|
# test @$() with aliases
|
|
|
|
#
|
|
|
|
(
|
|
|
|
"""
|
2017-04-21 17:46:04 -04:00
|
|
|
aliases['ls'] = 'spam spam sausage spam'
|
|
|
|
|
|
|
|
echo @$(which ls)
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"spam spam sausage spam\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
#
|
2020-04-01 22:45:01 +02:00
|
|
|
# test @$() without leading/trailig WS
|
|
|
|
#
|
|
|
|
(
|
|
|
|
"""
|
|
|
|
def _echo(args):
|
|
|
|
print(' '.join(args))
|
|
|
|
aliases['echo'] = _echo
|
|
|
|
|
|
|
|
echo foo_@$(echo spam)_bar
|
|
|
|
""",
|
|
|
|
"foo_spam_bar\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
#
|
|
|
|
# test @$() outer product
|
|
|
|
#
|
|
|
|
(
|
|
|
|
"""
|
|
|
|
def _echo(args):
|
|
|
|
print(' '.join(args))
|
|
|
|
aliases['echo'] = _echo
|
|
|
|
|
|
|
|
echo foo_@$(echo spam sausage)_bar
|
|
|
|
""",
|
|
|
|
"foo_spam_bar foo_sausage_bar\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
#
|
2018-08-30 09:18:49 -05:00
|
|
|
# test redirection
|
|
|
|
#
|
|
|
|
(
|
|
|
|
"""
|
2018-06-25 16:22:52 -04:00
|
|
|
echo Just the place for a snark. >tttt
|
2020-08-10 14:53:31 -04:00
|
|
|
python tests/bin/cat tttt
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"Just the place for a snark.\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
#
|
|
|
|
# Test completion registration and subproc stack
|
|
|
|
#
|
|
|
|
(
|
|
|
|
"""
|
2018-08-20 19:57:56 -04:00
|
|
|
def _f():
|
|
|
|
def j():
|
|
|
|
pass
|
|
|
|
|
|
|
|
global aliases
|
|
|
|
aliases['j'] = j
|
|
|
|
|
|
|
|
def completions(pref, *args):
|
|
|
|
return set(['hello', 'world'])
|
|
|
|
|
|
|
|
completer add j completions "start"
|
|
|
|
|
|
|
|
|
|
|
|
_f()
|
|
|
|
del _f
|
|
|
|
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"",
|
|
|
|
0,
|
|
|
|
),
|
2019-08-27 11:03:26 -04:00
|
|
|
#
|
|
|
|
# test single check_output
|
|
|
|
#
|
|
|
|
(
|
|
|
|
"""
|
|
|
|
def _echo(args):
|
|
|
|
print(' '.join(args))
|
|
|
|
aliases['echo'] = _echo
|
|
|
|
|
|
|
|
from xonsh.lib.subprocess import check_output
|
|
|
|
|
|
|
|
print(check_output(["echo", "hello"]).decode("utf8"))
|
|
|
|
""",
|
|
|
|
"hello\n\n",
|
|
|
|
0,
|
|
|
|
),
|
2019-10-01 16:56:27 -04:00
|
|
|
#
|
|
|
|
# test contextvars
|
|
|
|
#
|
|
|
|
(
|
|
|
|
"""
|
2019-10-01 17:01:20 -04:00
|
|
|
import sys
|
|
|
|
|
2019-10-03 10:27:38 -04:00
|
|
|
if sys.version_info[:2] >= (3, 7):
|
2019-10-01 17:01:20 -04:00
|
|
|
with open("sourced-file.xsh", "w") as f:
|
|
|
|
f.write('''
|
2019-10-01 16:56:27 -04:00
|
|
|
from contextvars import ContextVar
|
|
|
|
|
|
|
|
var = ContextVar('var', default='spam')
|
|
|
|
var.set('foo')
|
2019-10-01 17:01:20 -04:00
|
|
|
''')
|
2019-10-01 16:56:27 -04:00
|
|
|
|
2019-10-01 17:01:20 -04:00
|
|
|
source sourced-file.xsh
|
2019-10-01 16:56:27 -04:00
|
|
|
|
2019-10-01 17:01:20 -04:00
|
|
|
print("Var " + var.get())
|
2019-10-01 16:56:27 -04:00
|
|
|
|
2019-10-01 17:01:20 -04:00
|
|
|
import os
|
|
|
|
os.remove('sourced-file.xsh')
|
|
|
|
else:
|
|
|
|
print("Var foo")
|
2019-10-01 16:56:27 -04:00
|
|
|
""",
|
|
|
|
"Var foo\n",
|
|
|
|
0,
|
|
|
|
),
|
2020-05-10 16:17:55 +02:00
|
|
|
#
|
|
|
|
# test logical subprocess operators
|
|
|
|
#
|
|
|
|
(
|
|
|
|
"""
|
|
|
|
def _echo(args):
|
|
|
|
print(' '.join(args))
|
|
|
|
aliases['echo'] = _echo
|
|
|
|
|
|
|
|
echo --version and echo a
|
|
|
|
echo --version && echo a
|
|
|
|
echo --version or echo a
|
|
|
|
echo --version || echo a
|
|
|
|
echo -+version and echo a
|
|
|
|
echo -+version && echo a
|
|
|
|
echo -+version or echo a
|
|
|
|
echo -+version || echo a
|
|
|
|
echo -~version and echo a
|
|
|
|
echo -~version && echo a
|
|
|
|
echo -~version or echo a
|
|
|
|
echo -~version || echo a
|
|
|
|
""",
|
|
|
|
"""--version
|
|
|
|
a
|
|
|
|
--version
|
|
|
|
a
|
|
|
|
--version
|
|
|
|
--version
|
|
|
|
-+version
|
|
|
|
a
|
|
|
|
-+version
|
|
|
|
a
|
|
|
|
-+version
|
|
|
|
-+version
|
|
|
|
-~version
|
|
|
|
a
|
|
|
|
-~version
|
|
|
|
a
|
|
|
|
-~version
|
|
|
|
-~version
|
|
|
|
""",
|
|
|
|
0,
|
|
|
|
),
|
2016-10-13 02:03:30 -04:00
|
|
|
]
|
|
|
|
|
2021-05-10 16:30:41 +03:00
|
|
|
UNIX_TESTS = [
|
|
|
|
# testing alias stack: lambda function
|
|
|
|
(
|
|
|
|
"""
|
|
|
|
def _echo():
|
|
|
|
echo hello
|
|
|
|
|
|
|
|
aliases['echo'] = _echo
|
|
|
|
echo
|
|
|
|
""",
|
|
|
|
"hello\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
# testing alias stack: ExecAlias
|
|
|
|
(
|
|
|
|
"""
|
|
|
|
aliases['echo'] = "echo @('hello')"
|
|
|
|
echo
|
|
|
|
""",
|
|
|
|
"hello\n",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
# testing alias stack: callable alias (ExecAlias) + no binary location + infinite loop
|
|
|
|
(
|
|
|
|
"""
|
|
|
|
aliases['first'] = "second @(1)"
|
|
|
|
aliases['second'] = "first @(1)"
|
|
|
|
first
|
|
|
|
""",
|
|
|
|
lambda out: 'Recursive calls to "first" alias.' in out,
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
]
|
2016-10-13 02:03:30 -04:00
|
|
|
|
2021-05-20 15:44:26 +05:30
|
|
|
if not ON_WINDOWS:
|
|
|
|
ALL_PLATFORMS = tuple(ALL_PLATFORMS) + tuple(UNIX_TESTS)
|
|
|
|
|
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2018-08-30 09:18:49 -05:00
|
|
|
@pytest.mark.parametrize("case", ALL_PLATFORMS)
|
2016-10-13 02:03:30 -04:00
|
|
|
def test_script(case):
|
|
|
|
script, exp_out, exp_rtn = case
|
2016-10-16 21:08:37 +03:00
|
|
|
out, err, rtn = run_xonsh(script)
|
2021-05-10 16:30:41 +03:00
|
|
|
if callable(exp_out):
|
|
|
|
assert exp_out(out)
|
|
|
|
else:
|
|
|
|
assert exp_out == out
|
2016-10-16 21:08:37 +03:00
|
|
|
assert exp_rtn == rtn
|
2016-10-13 02:03:30 -04:00
|
|
|
|
2016-10-16 20:30:24 +03:00
|
|
|
|
2017-01-11 23:29:28 -05:00
|
|
|
ALL_PLATFORMS_STDERR = [
|
2018-08-30 09:18:49 -05:00
|
|
|
# test redirecting a function alias
|
|
|
|
(
|
|
|
|
"""
|
2017-12-07 23:24:06 -05:00
|
|
|
def _f(args, stdin, stdout):
|
2017-01-11 23:29:28 -05:00
|
|
|
print('Wow Mom!', file=stdout)
|
|
|
|
|
|
|
|
aliases['f'] = _f
|
|
|
|
f o>e
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
"Wow Mom!\n",
|
|
|
|
0,
|
|
|
|
)
|
2017-01-11 23:29:28 -05:00
|
|
|
]
|
|
|
|
|
2018-08-30 09:18:49 -05:00
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2018-08-30 09:18:49 -05:00
|
|
|
@pytest.mark.parametrize("case", ALL_PLATFORMS_STDERR)
|
2017-07-15 17:51:21 -05:00
|
|
|
def test_script_stderr(case):
|
2017-01-11 23:29:28 -05:00
|
|
|
script, exp_err, exp_rtn = case
|
|
|
|
out, err, rtn = run_xonsh(script, stderr=sp.PIPE)
|
|
|
|
assert exp_err == err
|
|
|
|
assert exp_rtn == rtn
|
|
|
|
|
2018-08-30 09:18:49 -05:00
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2016-10-16 20:30:24 +03:00
|
|
|
@skip_if_on_windows
|
2018-08-30 09:18:49 -05:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"cmd, fmt, exp",
|
|
|
|
[
|
|
|
|
("pwd", None, lambda: os.getcwd() + "\n"),
|
|
|
|
("echo WORKING", None, "WORKING\n"),
|
|
|
|
("ls -f", lambda out: out.splitlines().sort(), os.listdir().sort()),
|
2021-05-20 15:44:26 +05:30
|
|
|
(
|
|
|
|
"$FOO='foo' $BAR=2 xonsh -c r'echo -n $FOO$BAR'",
|
|
|
|
None,
|
|
|
|
"foo2",
|
|
|
|
),
|
2018-08-30 09:18:49 -05:00
|
|
|
],
|
|
|
|
)
|
2017-02-11 19:22:30 -05:00
|
|
|
def test_single_command_no_windows(cmd, fmt, exp):
|
2017-02-12 13:11:29 -05:00
|
|
|
check_run_xonsh(cmd, fmt, exp)
|
2017-02-11 19:22:30 -05:00
|
|
|
|
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2017-07-15 17:51:21 -05:00
|
|
|
def test_eof_syntax_error():
|
|
|
|
"""Ensures syntax errors for EOF appear on last line."""
|
2018-08-30 09:18:49 -05:00
|
|
|
script = "x = 1\na = (1, 0\n"
|
2017-07-15 17:51:21 -05:00
|
|
|
out, err, rtn = run_xonsh(script, stderr=sp.PIPE)
|
2018-08-30 09:18:49 -05:00
|
|
|
assert ":0:0: EOF in multi-line statement" not in err
|
|
|
|
assert ":2:0: EOF in multi-line statement" in err
|
2017-07-15 17:51:21 -05:00
|
|
|
|
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2018-07-20 19:21:15 -04:00
|
|
|
def test_open_quote_syntax_error():
|
2018-08-30 09:18:49 -05:00
|
|
|
script = (
|
|
|
|
"#!/usr/bin/env xonsh\n\n"
|
|
|
|
'echo "This is line 3"\n'
|
|
|
|
'print ("This is line 4")\n'
|
|
|
|
'x = "This is a string where I forget the closing quote on line 5\n'
|
|
|
|
'echo "This is line 6"\n'
|
|
|
|
)
|
2018-07-20 19:21:15 -04:00
|
|
|
out, err, rtn = run_xonsh(script, stderr=sp.PIPE)
|
|
|
|
assert """:3:5: ('code: "This is line 3"',)""" not in err
|
|
|
|
assert ':5:4: "' in err
|
2018-08-30 09:18:49 -05:00
|
|
|
assert "SyntaxError:" in err
|
2018-07-20 19:21:15 -04:00
|
|
|
|
|
|
|
|
2018-08-30 09:18:49 -05:00
|
|
|
_bad_case = pytest.mark.skipif(
|
|
|
|
ON_DARWIN or ON_WINDOWS or ON_TRAVIS, reason="bad platforms"
|
|
|
|
)
|
|
|
|
|
2017-02-12 13:11:29 -05:00
|
|
|
|
2021-06-11 07:11:19 -04:00
|
|
|
@skip_if_no_xonsh
|
|
|
|
def test_atdollar_no_output():
|
|
|
|
# see issue 1521
|
|
|
|
script = """
|
|
|
|
def _echo(args):
|
|
|
|
print(' '.join(args))
|
2021-06-14 01:47:05 -04:00
|
|
|
aliases['echo'] = _echo
|
2021-06-11 07:11:19 -04:00
|
|
|
@$(echo)
|
|
|
|
"""
|
|
|
|
out, err, rtn = run_xonsh(script, stderr=sp.PIPE)
|
|
|
|
assert "command is empty" in err
|
|
|
|
|
|
|
|
|
|
|
|
@skip_if_no_xonsh
|
|
|
|
def test_empty_command():
|
|
|
|
script = "$['']\n"
|
|
|
|
out, err, rtn = run_xonsh(script, stderr=sp.PIPE)
|
|
|
|
assert "command is empty" in err
|
|
|
|
|
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2017-02-12 13:11:29 -05:00
|
|
|
@_bad_case
|
|
|
|
def test_printfile():
|
2018-08-30 09:18:49 -05:00
|
|
|
check_run_xonsh("printfile.xsh", None, "printfile.xsh\n")
|
2017-02-12 13:11:29 -05:00
|
|
|
|
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2017-02-12 13:11:29 -05:00
|
|
|
@_bad_case
|
|
|
|
def test_printname():
|
2018-08-30 09:18:49 -05:00
|
|
|
check_run_xonsh("printfile.xsh", None, "printfile.xsh\n")
|
2017-02-12 13:11:29 -05:00
|
|
|
|
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2017-02-12 13:11:29 -05:00
|
|
|
@_bad_case
|
|
|
|
def test_sourcefile():
|
2018-08-30 09:18:49 -05:00
|
|
|
check_run_xonsh("printfile.xsh", None, "printfile.xsh\n")
|
2017-02-12 13:11:29 -05:00
|
|
|
|
2016-10-16 20:30:24 +03:00
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2017-02-25 21:45:32 -05:00
|
|
|
@_bad_case
|
2018-08-30 09:18:49 -05:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"cmd, fmt, exp",
|
|
|
|
[
|
|
|
|
# test subshell wrapping
|
|
|
|
(
|
|
|
|
"""
|
2017-02-25 21:45:32 -05:00
|
|
|
with open('tttt', 'w') as fp:
|
|
|
|
fp.write("Wow mom!\\n")
|
|
|
|
|
|
|
|
(wc) < tttt
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
None,
|
|
|
|
" 1 2 9 <stdin>\n",
|
|
|
|
),
|
|
|
|
# test subshell statement wrapping
|
|
|
|
(
|
|
|
|
"""
|
2017-02-25 21:45:32 -05:00
|
|
|
with open('tttt', 'w') as fp:
|
|
|
|
fp.write("Wow mom!\\n")
|
|
|
|
|
|
|
|
(wc;) < tttt
|
2018-08-30 09:18:49 -05:00
|
|
|
""",
|
|
|
|
None,
|
|
|
|
" 1 2 9 <stdin>\n",
|
|
|
|
),
|
|
|
|
],
|
|
|
|
)
|
2017-02-25 21:45:32 -05:00
|
|
|
def test_subshells(cmd, fmt, exp):
|
|
|
|
check_run_xonsh(cmd, fmt, exp)
|
|
|
|
|
2016-10-16 20:30:24 +03:00
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2016-10-16 20:30:24 +03:00
|
|
|
@skip_if_on_windows
|
2018-08-30 09:18:49 -05:00
|
|
|
@pytest.mark.parametrize("cmd, exp", [("pwd", lambda: os.getcwd() + "\n")])
|
2016-10-16 21:08:37 +03:00
|
|
|
def test_redirect_out_to_file(cmd, exp, tmpdir):
|
2018-08-30 09:18:49 -05:00
|
|
|
outfile = tmpdir.mkdir("xonsh_test_dir").join("xonsh_test_file")
|
|
|
|
command = "{} > {}\n".format(cmd, outfile)
|
2016-10-16 21:43:38 +03:00
|
|
|
out, _, _ = run_xonsh(command)
|
2016-10-16 20:30:24 +03:00
|
|
|
content = outfile.read()
|
2016-10-26 00:40:47 -04:00
|
|
|
if callable(exp):
|
|
|
|
exp = exp()
|
2016-10-16 20:30:24 +03:00
|
|
|
assert content == exp
|
2019-02-06 14:51:52 -05:00
|
|
|
|
|
|
|
|
|
|
|
@skip_if_no_make
|
|
|
|
@skip_if_no_xonsh
|
|
|
|
@skip_if_no_sleep
|
2019-02-06 15:23:41 -05:00
|
|
|
@skip_if_on_windows
|
2020-05-08 15:35:08 -04:00
|
|
|
@pytest.mark.xfail(strict=False) # TODO: fixme (super flaky on OSX)
|
2019-02-06 14:51:52 -05:00
|
|
|
def test_xonsh_no_close_fds():
|
|
|
|
# see issue https://github.com/xonsh/xonsh/issues/2984
|
|
|
|
makefile = (
|
|
|
|
"default: all\n"
|
|
|
|
"all:\n"
|
|
|
|
"\t$(MAKE) s\n"
|
|
|
|
"s:\n"
|
|
|
|
"\t$(MAKE) a b\n"
|
|
|
|
"a:\n"
|
|
|
|
"\tsleep 1\n"
|
|
|
|
"b:\n"
|
2019-02-06 14:54:51 -05:00
|
|
|
"\tsleep 1\n"
|
|
|
|
)
|
2019-02-06 14:51:52 -05:00
|
|
|
with tempfile.TemporaryDirectory() as d, indir(d):
|
2019-02-06 14:54:51 -05:00
|
|
|
with open("Makefile", "w") as f:
|
2019-02-06 14:51:52 -05:00
|
|
|
f.write(makefile)
|
2019-02-06 14:54:51 -05:00
|
|
|
out = sp.check_output(["make", "-sj2", "SHELL=xonsh"], universal_newlines=True)
|
2019-02-06 14:51:52 -05:00
|
|
|
assert "warning" not in out
|
2020-01-12 14:45:52 -05:00
|
|
|
|
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2020-01-12 14:45:52 -05:00
|
|
|
@pytest.mark.parametrize(
|
2020-05-08 15:35:08 -04:00
|
|
|
"cmd, fmt, exp",
|
2021-05-20 15:44:26 +05:30
|
|
|
[
|
|
|
|
("cat tttt | wc", lambda x: x > "", True),
|
|
|
|
], # noqa E231 (black removes space)
|
2020-01-12 14:45:52 -05:00
|
|
|
)
|
|
|
|
def test_pipe_between_subprocs(cmd, fmt, exp):
|
|
|
|
"verify pipe between subprocesses doesn't throw an exception"
|
|
|
|
check_run_xonsh(cmd, fmt, exp)
|
|
|
|
|
2020-03-01 15:06:33 -05:00
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2020-03-01 15:06:33 -05:00
|
|
|
@skip_if_on_windows
|
|
|
|
def test_negative_exit_codes_fail():
|
|
|
|
# see issue 3309
|
|
|
|
script = 'python -c "import os; os.abort()" && echo OK\n'
|
|
|
|
out, err, rtn = run_xonsh(script)
|
2020-05-05 06:42:28 -04:00
|
|
|
assert "OK" != out
|
|
|
|
assert "OK" != err
|
2020-04-07 15:07:24 +02:00
|
|
|
|
2020-04-07 23:10:35 +02:00
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2020-04-07 15:07:24 +02:00
|
|
|
@pytest.mark.parametrize(
|
2020-04-07 23:10:35 +02:00
|
|
|
"cmd, exp",
|
2020-04-07 15:07:24 +02:00
|
|
|
[
|
2020-04-07 23:10:35 +02:00
|
|
|
("echo '&'", "&\n"),
|
|
|
|
("echo foo'&'", "foo'&'\n"),
|
|
|
|
("echo foo '&'", "foo &\n"),
|
|
|
|
("echo foo '&' bar", "foo & bar\n"),
|
2020-04-07 15:07:24 +02:00
|
|
|
],
|
|
|
|
)
|
2020-04-07 23:10:35 +02:00
|
|
|
def test_ampersand_argument(cmd, exp):
|
|
|
|
script = """
|
|
|
|
#!/usr/bin/env xonsh
|
|
|
|
def _echo(args):
|
|
|
|
print(' '.join(args))
|
|
|
|
aliases['echo'] = _echo
|
|
|
|
{}
|
|
|
|
""".format(
|
|
|
|
cmd
|
|
|
|
)
|
|
|
|
out, _, _ = run_xonsh(script)
|
|
|
|
assert out == exp
|
2020-07-28 17:35:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
# issue 3402
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2020-07-28 17:35:16 +02:00
|
|
|
@skip_if_on_windows
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"cmd, exp_rtn",
|
|
|
|
[
|
2021-07-24 07:17:37 -07:00
|
|
|
("import sys; sys.exit(0)", 0),
|
|
|
|
("import sys; sys.exit(100)", 100),
|
2020-07-29 08:55:48 +02:00
|
|
|
("sh -c 'exit 0'", 0),
|
|
|
|
("sh -c 'exit 1'", 1),
|
2020-07-28 17:35:16 +02:00
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_single_command_return_code(cmd, exp_rtn):
|
|
|
|
_, _, rtn = run_xonsh(cmd, single_command=True)
|
|
|
|
assert rtn == exp_rtn
|
2020-08-05 13:15:56 +02:00
|
|
|
|
|
|
|
|
2020-08-10 16:54:45 -04:00
|
|
|
@skip_if_no_xonsh
|
2020-08-05 13:15:56 +02:00
|
|
|
@skip_if_on_msys
|
|
|
|
@skip_if_on_windows
|
|
|
|
@skip_if_on_darwin
|
|
|
|
def test_argv0():
|
|
|
|
check_run_xonsh("checkargv0.xsh", None, "OK\n")
|
2021-05-28 15:42:37 +03:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("interactive", [True, False])
|
|
|
|
def test_loading_correctly(monkeypatch, interactive):
|
|
|
|
# Ensure everything loads correctly in interactive mode (e.g. #4289)
|
|
|
|
monkeypatch.setenv("SHELL_TYPE", "prompt_toolkit")
|
|
|
|
monkeypatch.setenv("XONSH_LOGIN", "1")
|
|
|
|
monkeypatch.setenv("XONSH_INTERACTIVE", "1")
|
|
|
|
out, err, ret = run_xonsh(
|
|
|
|
"import xonsh; echo -n AAA @(xonsh.__file__) BBB",
|
|
|
|
interactive=interactive,
|
|
|
|
single_command=True,
|
|
|
|
)
|
|
|
|
assert not err
|
|
|
|
assert ret == 0
|
|
|
|
our_xonsh = (
|
|
|
|
xonsh.__file__
|
|
|
|
) # make sure xonsh didn't fail and fallback to the system shell
|
|
|
|
assert f"AAA {our_xonsh} BBB" in out # ignore tty warnings/prompt text
|
2021-07-24 07:17:37 -07:00
|
|
|
|
|
|
|
|
|
|
|
@skip_if_no_xonsh
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"cmd",
|
|
|
|
[
|
|
|
|
"x = 0; (lambda: x)()",
|
|
|
|
"x = 0; [x for _ in [0]]",
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_exec_function_scope(cmd):
|
|
|
|
_, _, rtn = run_xonsh(cmd, single_command=True)
|
|
|
|
assert rtn == 0
|