2016-11-14 21:09:25 +02:00
|
|
|
import os
|
2018-11-09 10:08:03 +01:00
|
|
|
import sys
|
2021-05-20 15:44:26 +05:30
|
|
|
import types
|
|
|
|
import typing as tp
|
|
|
|
from unittest.mock import MagicMock
|
2016-07-05 09:10:22 +02:00
|
|
|
|
2016-06-25 01:15:48 +03:00
|
|
|
import pytest
|
2016-08-18 21:49:18 +02:00
|
|
|
|
2022-01-31 21:26:34 +05:30
|
|
|
from tools import DummyHistory, DummyShell, copy_env, sp
|
|
|
|
from xonsh import commands_cache
|
2021-07-25 15:45:05 +05:30
|
|
|
from xonsh.aliases import Aliases
|
2022-01-31 21:26:34 +05:30
|
|
|
from xonsh.built_ins import XSH, XonshSession
|
2021-09-26 21:03:09 +05:30
|
|
|
from xonsh.completer import Completer
|
2022-01-31 21:26:34 +05:30
|
|
|
from xonsh.events import events
|
2016-07-01 15:43:16 +03:00
|
|
|
from xonsh.execer import Execer
|
2016-09-24 16:09:01 -04:00
|
|
|
from xonsh.jobs import tasks
|
2021-05-11 13:10:58 +03:00
|
|
|
from xonsh.parsers.completion_context import CompletionContextParser
|
2016-09-09 00:08:13 -04:00
|
|
|
|
2016-07-05 09:10:22 +02:00
|
|
|
|
2016-11-14 21:09:25 +02:00
|
|
|
@pytest.fixture
|
|
|
|
def source_path():
|
|
|
|
"""Get the xonsh source path."""
|
|
|
|
pwd = os.path.dirname(__file__)
|
|
|
|
return os.path.dirname(pwd)
|
|
|
|
|
|
|
|
|
2016-07-01 15:43:16 +03:00
|
|
|
@pytest.fixture
|
2022-01-08 04:03:22 +05:30
|
|
|
def xonsh_execer(monkeypatch, xonsh_session):
|
2016-07-03 12:00:24 +03:00
|
|
|
"""Initiate the Execer with a mocked nop `load_builtins`"""
|
2022-01-08 04:03:22 +05:30
|
|
|
yield xonsh_session.execer
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def xonsh_execer_exec(xonsh_execer):
|
|
|
|
def factory(input, **kwargs):
|
|
|
|
xonsh_execer.exec(input, **kwargs)
|
|
|
|
return True
|
|
|
|
|
|
|
|
return factory
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def xonsh_execer_parse(xonsh_execer):
|
|
|
|
def factory(input):
|
|
|
|
tree = XSH.execer.parse(input, ctx=None)
|
|
|
|
return tree
|
|
|
|
|
|
|
|
return factory
|
2021-05-20 15:44:26 +05:30
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def patch_commands_cache_bins(xession, tmp_path, monkeypatch):
|
|
|
|
def _factory(binaries: tp.List[str]):
|
2022-01-08 04:03:22 +05:30
|
|
|
xession.env["PATH"] = [tmp_path]
|
2021-05-20 15:44:26 +05:30
|
|
|
exec_mock = MagicMock(return_value=binaries)
|
|
|
|
monkeypatch.setattr(commands_cache, "executables_in", exec_mock)
|
2022-01-08 04:03:22 +05:30
|
|
|
return xession.commands_cache
|
2021-05-20 15:44:26 +05:30
|
|
|
|
|
|
|
return _factory
|
2016-07-01 15:43:16 +03:00
|
|
|
|
2016-06-25 01:15:48 +03:00
|
|
|
|
2022-01-08 04:03:22 +05:30
|
|
|
@pytest.fixture
|
|
|
|
def patch_locate_binary(monkeypatch):
|
|
|
|
def locate_binary(self, name):
|
|
|
|
return os.path.join(os.path.dirname(__file__), "bin", name)
|
|
|
|
|
|
|
|
def factory(cc: commands_cache.CommandsCache):
|
|
|
|
monkeypatch.setattr(cc, "locate_binary", types.MethodType(locate_binary, cc))
|
|
|
|
return cc
|
|
|
|
|
|
|
|
return factory
|
|
|
|
|
|
|
|
|
2018-11-09 10:08:03 +01:00
|
|
|
@pytest.fixture
|
|
|
|
def monkeypatch_stderr(monkeypatch):
|
|
|
|
"""Monkeypath sys.stderr with no ResourceWarning."""
|
|
|
|
with open(os.devnull, "w") as fd:
|
|
|
|
monkeypatch.setattr(sys, "stderr", fd)
|
|
|
|
yield
|
|
|
|
|
|
|
|
|
2018-11-19 20:22:18 -05:00
|
|
|
@pytest.fixture
|
2017-01-08 20:31:39 -05:00
|
|
|
def xonsh_events():
|
|
|
|
yield events
|
|
|
|
for name, oldevent in vars(events).items():
|
|
|
|
# Heavily based on transmogrification
|
2017-01-12 13:29:15 -05:00
|
|
|
species = oldevent.species
|
|
|
|
newevent = events._mkevent(name, species, species.__doc__)
|
2017-01-08 20:31:39 -05:00
|
|
|
setattr(events, name, newevent)
|
|
|
|
|
|
|
|
|
2021-08-10 12:47:20 +05:30
|
|
|
@pytest.fixture(scope="session")
|
2022-01-08 04:03:22 +05:30
|
|
|
def session_os_env():
|
|
|
|
"""Env with values from os.environ like real session"""
|
2021-08-10 12:47:20 +05:30
|
|
|
from xonsh.environ import Env, default_env
|
2022-01-08 04:03:22 +05:30
|
|
|
|
|
|
|
return Env(default_env())
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def session_env():
|
|
|
|
"""Env with some initial values that doesn't load from os.environ"""
|
|
|
|
from xonsh.environ import Env
|
|
|
|
|
|
|
|
initial_vars = {
|
|
|
|
"UPDATE_OS_ENVIRON": False,
|
|
|
|
"XONSH_DEBUG": 1,
|
|
|
|
"XONSH_COLOR_STYLE": "default",
|
|
|
|
"VC_BRANCH_TIMEOUT": 1,
|
|
|
|
"XONSH_ENCODING": "utf-8",
|
|
|
|
"XONSH_ENCODING_ERRORS": "strict",
|
|
|
|
"COMMANDS_CACHE_SAVE_INTERMEDIATE": False,
|
2021-08-10 12:47:20 +05:30
|
|
|
}
|
2022-01-08 04:03:22 +05:30
|
|
|
env = Env(initial_vars)
|
|
|
|
return env
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def session_execer():
|
|
|
|
return Execer()
|
2021-08-10 12:47:20 +05:30
|
|
|
|
|
|
|
|
2018-11-19 20:22:18 -05:00
|
|
|
@pytest.fixture
|
2022-01-08 04:03:22 +05:30
|
|
|
def os_env(session_os_env):
|
|
|
|
"""A mutable copy of Original session_os_env"""
|
2021-08-10 12:47:20 +05:30
|
|
|
|
2022-01-08 04:03:22 +05:30
|
|
|
return copy_env(session_os_env)
|
2021-05-20 15:44:26 +05:30
|
|
|
|
|
|
|
|
2022-01-08 04:03:22 +05:30
|
|
|
@pytest.fixture
|
|
|
|
def env(tmpdir, session_env):
|
|
|
|
"""a mutable copy of session_env"""
|
|
|
|
env_copy = copy_env(session_env)
|
|
|
|
initial_vars = {"XONSH_DATA_DIR": str(tmpdir)}
|
|
|
|
|
|
|
|
env_copy.update(initial_vars)
|
|
|
|
return env_copy
|
2021-09-15 22:14:28 +03:00
|
|
|
|
2022-01-08 04:03:22 +05:30
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def xonsh_session(xonsh_events, session_execer, os_env, monkeypatch) -> XonshSession:
|
|
|
|
"""a fixture to use where XonshSession is fully loaded without any mocks"""
|
|
|
|
|
|
|
|
XSH.load(
|
|
|
|
ctx={},
|
|
|
|
execer=session_execer,
|
|
|
|
commands_cache=commands_cache.CommandsCache(),
|
|
|
|
env=os_env,
|
|
|
|
)
|
|
|
|
yield XSH
|
|
|
|
XSH.unload()
|
2016-09-24 16:13:14 -04:00
|
|
|
tasks.clear() # must to this to enable resetting all_jobs
|
2020-05-06 21:23:57 -04:00
|
|
|
|
|
|
|
|
2021-05-20 15:44:26 +05:30
|
|
|
@pytest.fixture
|
2022-01-08 04:03:22 +05:30
|
|
|
def mock_xonsh_session(monkeypatch, xonsh_events, xonsh_session, env):
|
|
|
|
"""Mock out most of the builtins xonsh attributes."""
|
|
|
|
|
|
|
|
# make sure that all other fixtures call this mock only one time
|
|
|
|
session = []
|
|
|
|
|
|
|
|
def factory(*attrs: str):
|
|
|
|
"""
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
attrs
|
|
|
|
do not mock the given attributes
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
XonshSession
|
|
|
|
with most of the attributes mocked out
|
|
|
|
"""
|
|
|
|
if session:
|
|
|
|
raise RuntimeError("The factory should be called only once per test")
|
|
|
|
|
|
|
|
for attr, val in [
|
|
|
|
("env", env),
|
|
|
|
("shell", DummyShell()),
|
|
|
|
("help", lambda x: x),
|
|
|
|
("aliases", Aliases()),
|
|
|
|
("exit", False),
|
|
|
|
("history", DummyHistory()),
|
|
|
|
(
|
|
|
|
"commands_cache",
|
|
|
|
commands_cache.CommandsCache(),
|
|
|
|
), # since env,aliases change , patch cmds-cache
|
|
|
|
# ("subproc_captured", sp),
|
|
|
|
("subproc_uncaptured", sp),
|
|
|
|
("subproc_captured_stdout", sp),
|
|
|
|
("subproc_captured_inject", sp),
|
|
|
|
("subproc_captured_object", sp),
|
|
|
|
("subproc_captured_hiddenobject", sp),
|
|
|
|
]:
|
|
|
|
if attr in attrs:
|
|
|
|
continue
|
|
|
|
monkeypatch.setattr(xonsh_session, attr, val)
|
|
|
|
|
|
|
|
for attr, val in [
|
|
|
|
("evalx", eval),
|
|
|
|
("execx", None),
|
|
|
|
("compilex", None),
|
|
|
|
# Unlike all the other stuff, this has to refer to the "real" one because all modules that would
|
|
|
|
# be firing events on the global instance.
|
|
|
|
("events", xonsh_events),
|
|
|
|
]:
|
|
|
|
# attributes to builtins are dynamicProxy and should pickup the following
|
|
|
|
monkeypatch.setattr(xonsh_session.builtins, attr, val)
|
|
|
|
|
|
|
|
session.append(xonsh_session)
|
|
|
|
return xonsh_session
|
|
|
|
|
|
|
|
yield factory
|
|
|
|
session.clear()
|
2021-05-20 15:44:26 +05:30
|
|
|
|
|
|
|
|
2021-08-28 16:39:59 +05:30
|
|
|
@pytest.fixture
|
2022-01-08 04:03:22 +05:30
|
|
|
def xession(mock_xonsh_session) -> XonshSession:
|
|
|
|
"""Mock out most of the builtins xonsh attributes."""
|
|
|
|
return mock_xonsh_session()
|
2021-08-28 16:39:59 +05:30
|
|
|
|
2022-01-08 04:03:22 +05:30
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def xsh_with_aliases(mock_xonsh_session) -> XonshSession:
|
2022-01-27 21:22:36 +05:30
|
|
|
"""Xonsh mock-session with default set of aliases"""
|
2022-01-08 04:03:22 +05:30
|
|
|
return mock_xonsh_session("aliases")
|
2021-08-28 16:39:59 +05:30
|
|
|
|
|
|
|
|
2022-01-27 21:22:36 +05:30
|
|
|
@pytest.fixture
|
|
|
|
def xsh_with_env(mock_xonsh_session) -> XonshSession:
|
|
|
|
"""Xonsh mock-session with os.environ"""
|
|
|
|
return mock_xonsh_session("env")
|
|
|
|
|
|
|
|
|
2021-05-11 13:10:58 +03:00
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def completion_context_parse():
|
|
|
|
return CompletionContextParser().parse
|
|
|
|
|
|
|
|
|
2022-01-10 21:51:22 +05:30
|
|
|
@pytest.fixture(scope="session")
|
|
|
|
def completer_obj():
|
|
|
|
return Completer()
|
|
|
|
|
|
|
|
|
2021-08-26 04:02:13 +05:30
|
|
|
@pytest.fixture
|
2022-01-10 21:51:22 +05:30
|
|
|
def check_completer(completer_obj):
|
2021-09-26 21:03:09 +05:30
|
|
|
"""Helper function to run completer and parse the results as set of strings"""
|
2022-01-10 21:51:22 +05:30
|
|
|
completer = completer_obj
|
2021-09-26 21:03:09 +05:30
|
|
|
|
2022-01-27 21:22:36 +05:30
|
|
|
def _factory(
|
|
|
|
line: str, prefix: "None|str" = "", send_original=False, complete_fn=None
|
|
|
|
):
|
|
|
|
"""
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
----------
|
|
|
|
line
|
|
|
|
prefix
|
|
|
|
send_original
|
|
|
|
if True, return the original result from the completer (e.g. RichCompletion instances ...)
|
|
|
|
complete_fn
|
|
|
|
if given, use that to get the completions
|
|
|
|
|
|
|
|
Returns
|
|
|
|
-------
|
|
|
|
completions as set of string if not send
|
|
|
|
"""
|
|
|
|
if prefix is not None:
|
|
|
|
line += " " + prefix
|
|
|
|
if complete_fn is None:
|
|
|
|
completions, _ = completer.complete_line(line)
|
|
|
|
else:
|
|
|
|
ctx = completer_obj.parse(line)
|
|
|
|
out = complete_fn(ctx)
|
|
|
|
if isinstance(out, tuple):
|
|
|
|
completions = out[0]
|
|
|
|
else:
|
|
|
|
completions = out
|
2021-12-12 08:47:47 +05:30
|
|
|
values = {getattr(i, "value", i).strip() for i in completions}
|
|
|
|
|
|
|
|
if send_original:
|
|
|
|
# just return the bare completions without appended-space for easier assertions
|
|
|
|
return values, completions
|
|
|
|
|
|
|
|
return values
|
2021-08-26 04:02:13 +05:30
|
|
|
|
|
|
|
return _factory
|
|
|
|
|
|
|
|
|
2021-06-07 23:10:40 +05:30
|
|
|
@pytest.fixture
|
|
|
|
def ptk_shell(xonsh_execer):
|
|
|
|
from prompt_toolkit.input import create_pipe_input
|
|
|
|
from prompt_toolkit.output import DummyOutput
|
2022-01-31 21:26:34 +05:30
|
|
|
|
2021-06-07 23:10:40 +05:30
|
|
|
from xonsh.ptk_shell.shell import PromptToolkitShell
|
|
|
|
|
|
|
|
inp = create_pipe_input()
|
|
|
|
out = DummyOutput()
|
|
|
|
shell = PromptToolkitShell(
|
|
|
|
execer=xonsh_execer, ctx={}, ptk_args={"input": inp, "output": out}
|
|
|
|
)
|
|
|
|
yield inp, out, shell
|
|
|
|
inp.close()
|
|
|
|
|
|
|
|
|
2021-09-03 00:45:20 +05:30
|
|
|
@pytest.fixture
|
|
|
|
def readline_shell(xonsh_execer, tmpdir, mocker):
|
|
|
|
from xonsh.readline_shell import ReadlineShell
|
|
|
|
|
|
|
|
inp_path = tmpdir / "in"
|
|
|
|
inp = inp_path.open("w+")
|
|
|
|
out_path = tmpdir / "out"
|
|
|
|
out = out_path.open("w+")
|
|
|
|
|
|
|
|
shell = ReadlineShell(execer=xonsh_execer, ctx={}, stdin=inp, stdout=out)
|
|
|
|
mocker.patch.object(shell, "_load_remaining_input_into_queue")
|
|
|
|
yield shell
|
|
|
|
inp.close()
|
|
|
|
out.close()
|
|
|
|
|
|
|
|
|
2020-05-06 21:23:57 -04:00
|
|
|
def pytest_configure(config):
|
|
|
|
"""Abort test run if --flake8 requested, since it would hang on parser_test.py"""
|
2020-08-10 16:25:58 +02:00
|
|
|
if config.getoption("--flake8", ""):
|
2020-05-06 21:23:57 -04:00
|
|
|
pytest.exit("pytest-flake8 no longer supported, use flake8 instead.")
|
2021-12-22 11:17:53 +05:30
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def load_xontrib():
|
|
|
|
to_unload = []
|
|
|
|
|
|
|
|
def wrapper(*names: str):
|
|
|
|
from xonsh.xontribs import xontribs_load
|
|
|
|
|
|
|
|
for name in names:
|
|
|
|
module = f"xontrib.{name}"
|
|
|
|
if module not in sys.modules:
|
|
|
|
to_unload.append(module)
|
|
|
|
|
|
|
|
xontribs_load([name])
|
|
|
|
return
|
|
|
|
|
|
|
|
yield wrapper
|
|
|
|
|
|
|
|
for mod in to_unload:
|
|
|
|
del sys.modules[mod]
|