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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
"""Test initialization of prompt_toolkit shell"""
import sys
import pyte
import pytest
from xonsh.platform import minimum_required_ptk_version
from xonsh.ptk_shell.shell import tokenize_ansi
from xonsh.shell import Shell
# verify error if ptk not installed or below min
@pytest.mark.parametrize(
"ptk_ver, ini_shell_type, exp_shell_type, warn_snip",
[
(None, "prompt_toolkit", "readline", None),
((0, 5, 7), "prompt_toolkit", "readline", "is not supported"),
((1, 0, 0), "prompt_toolkit", "readline", "is not supported"),
((2, 0, 0), "prompt_toolkit", "prompt_toolkit", None),
((2, 0, 0), "best", "prompt_toolkit", None),
((2, 0, 0), "readline", "readline", None),
((3, 0, 0), "prompt_toolkit", "prompt_toolkit", None),
((3, 0, 0), "best", "prompt_toolkit", None),
((3, 0, 0), "readline", "readline", None),
((4, 0, 0), "prompt_toolkit", "prompt_toolkit", None),
],
)
def test_prompt_toolkit_version_checks(
ptk_ver,
ini_shell_type,
exp_shell_type,
warn_snip,
monkeypatch,
xession,
):
mocked_warn = ""
def mock_warning(msg):
nonlocal mocked_warn
mocked_warn = msg
return
def mock_ptk_above_min_supported():
nonlocal ptk_ver
return ptk_ver and (ptk_ver[:3] >= minimum_required_ptk_version)
def mock_has_prompt_toolkit():
nonlocal ptk_ver
return ptk_ver is not None
monkeypatch.setattr(
"xonsh.shell.warnings.warn", mock_warning
) # hardwon: patch the caller!
monkeypatch.setattr(
"xonsh.shell.ptk_above_min_supported", mock_ptk_above_min_supported
) # have to patch both callers
monkeypatch.setattr(
"xonsh.platform.ptk_above_min_supported", mock_ptk_above_min_supported
)
monkeypatch.setattr("xonsh.platform.has_prompt_toolkit", mock_has_prompt_toolkit)
old_syspath = sys.path.copy()
act_shell_type = Shell.choose_shell_type(ini_shell_type, {})
assert len(old_syspath) == len(sys.path)
sys.path = old_syspath
assert act_shell_type == exp_shell_type
if warn_snip:
assert warn_snip in mocked_warn
pass
@pytest.mark.parametrize(
"prompt_tokens, ansi_string_parts",
[
# no ansi, single token
([("fake style", "no ansi here")], ["no ansi here"]),
# no ansi, multiple tokens
([("s1", "no"), ("s2", "ansi here")], ["no", "ansi here"]),
# ansi only, multiple
([("s1", "\x1b[33mansi \x1b[1monly")], ["", "ansi ", "only"]),
# mixed
(
[("s1", "no ansi"), ("s2", "mixed \x1b[33mansi")],
["no ansi", "mixed ", "ansi"],
),
],
)
def test_tokenize_ansi(prompt_tokens, ansi_string_parts):
ansi_tokens = tokenize_ansi(prompt_tokens)
for token, text in zip(ansi_tokens, ansi_string_parts):
assert token[1] == text
@pytest.mark.parametrize(
"line, exp",
[
[repr("hello"), None],
["2 * 3", "6"],
],
)
def test_ptk_prompt(line, exp, ptk_shell, capsys):
inp, out, shell = ptk_shell
inp.send_text(f"{line}\nexit\n") # note: terminate with '\n'
shell.cmdloop()
screen = pyte.Screen(80, 24)
stream = pyte.Stream(screen)
out, _ = capsys.readouterr()
# this will remove render any color codes
stream.feed(out.strip())
out = screen.display[0].strip()
assert out.strip() == (exp or line)
@pytest.mark.parametrize(
"cmd,exp_append_history",
[
("", False),
("# a comment", False),
("print('yes')", True),
],
)
def test_ptk_default_append_history(cmd, exp_append_history, ptk_shell, monkeypatch):
"""Test that running an empty line or a comment does not append to history.
This test is necessary because the prompt-toolkit shell uses a custom _push() method that is different from the base shell's push() method."""
inp, out, shell = ptk_shell
append_history_calls = []
def mock_append_history(**info):
append_history_calls.append(info)
monkeypatch.setattr(shell, "_append_history", mock_append_history)
shell.default(cmd)
if exp_append_history:
assert len(append_history_calls) == 1
else:
assert len(append_history_calls) == 0
|