xonsh/tests/test_completer.py
Noorhteen Raja NJ 769dfbe6aa
Py 312 pre-liminary support (#5156)
* refactor: project requires 3.9+

changed as per NEP-29
https://numpy.org/neps/nep-0029-deprecation_policy.html

* test: nose type tests are deprecated in pytest now

* fix: deprecation of ast.Str and ast.Bytes and .s attribute access

* fix: deprecation of ast.Num,ast.NameConstant,ast.Ellipsis

* refactor: upgrade code to be py39+ using ruff

the changes are auto-generated

* refactor: remove typing.Annotated compatibility code

* fix: temporarily disable having xonsh syntax inside f-strings

* test: skip failing tests

there is no workaround for this version. It might get solved in the
final release though

* refactor: make XonshSession.completer lazily populated

this speedsup the tests as cmd_cache would not be actively populated
when used in default_completers function

* refactor: make presence of walrus operator default
2023-07-04 22:18:37 +05:30

157 lines
4.5 KiB
Python

"""Tests for the base completer's logic (xonsh/completer.py)"""
import pytest
from xonsh.completer import Completer
from xonsh.completers.tools import (
RichCompletion,
contextual_command_completer,
non_exclusive_completer,
)
from xonsh.parsers.completion_context import CommandContext
@pytest.fixture(scope="session")
def completer():
return Completer()
@pytest.fixture
def completers_mock(xession, monkeypatch):
completers = {}
monkeypatch.setattr(xession, "_completers", completers)
return completers
def test_sanity(completer, completers_mock):
# no completions:
completers_mock["a"] = lambda *a: None
assert completer.complete("", "", 0, 0) == ((), 0)
# simple completion:
completers_mock["a"] = lambda *a: {"comp"}
assert completer.complete("pre", "", 0, 0) == (("comp",), 3)
# multiple completions:
completers_mock["a"] = lambda *a: {"comp1", "comp2"}
assert completer.complete("pre", "", 0, 0) == (("comp1", "comp2"), 3)
# custom lprefix:
completers_mock["a"] = lambda *a: ({"comp"}, 2)
assert completer.complete("pre", "", 0, 0) == (("comp",), 2)
# RichCompletion:
completers_mock["a"] = lambda *a: {RichCompletion("comp", prefix_len=5)}
assert completer.complete("pre", "", 0, 0) == (
(RichCompletion("comp", prefix_len=5),),
3,
)
def test_cursor_after_closing_quote(completer, completers_mock):
"""See ``Completer.complete`` in ``xonsh/completer.py``"""
@contextual_command_completer
def comp(context: CommandContext):
return {context.prefix + "1", context.prefix + "2"}
completers_mock["a"] = comp
assert completer.complete(
"", "", 0, 0, {}, multiline_text="'test'", cursor_index=6
) == (("test1'", "test2'"), 5)
assert completer.complete(
"", "", 0, 0, {}, multiline_text="'''test'''", cursor_index=10
) == (("test1'''", "test2'''"), 7)
def test_cursor_after_closing_quote_override(completer, completers_mock):
"""Test overriding the default values"""
@contextual_command_completer
def comp(context: CommandContext):
return {
# replace the closing quote with "a"
RichCompletion(
"a", prefix_len=len(context.closing_quote), append_closing_quote=False
),
# add text after the closing quote
RichCompletion(context.prefix + "_no_quote", append_closing_quote=False),
# sanity
RichCompletion(context.prefix + "1"),
}
completers_mock["a"] = comp
assert completer.complete(
"", "", 0, 0, {}, multiline_text="'test'", cursor_index=6
) == (
(
"a",
"test1'",
"test_no_quote",
),
5,
)
assert completer.complete(
"", "", 0, 0, {}, multiline_text="'''test'''", cursor_index=10
) == (
(
"a",
"test1'''",
"test_no_quote",
),
7,
)
def test_append_space(completer, completers_mock):
@contextual_command_completer
def comp(context: CommandContext):
return {
RichCompletion(context.prefix + "a", append_space=True),
RichCompletion(context.prefix + " ", append_space=False), # bad usage
RichCompletion(
context.prefix + "b", append_space=True, append_closing_quote=False
),
}
completers_mock["a"] = comp
assert completer.complete(
"", "", 0, 0, {}, multiline_text="'test'", cursor_index=6
) == (
(
"test '",
"testa' ",
"testb ",
),
5,
)
@pytest.mark.parametrize(
"middle_result, exp",
(
(
# stop at the first exclusive result
({"b1", "b2"}, ("a1", "a2", "b1", "b2")),
# pass empty exclusive results
({}, ("a1", "a2", "c1", "c2")),
# pass empty exclusive results
(None, ("a1", "a2", "c1", "c2")),
# stop at StopIteration
(StopIteration, ("a1", "a2")),
)
),
)
def test_non_exclusive(completer, completers_mock, middle_result, exp):
completers_mock["a"] = non_exclusive_completer(lambda *a: {"a1", "a2"})
def middle(*a):
if middle_result is StopIteration:
raise StopIteration()
return middle_result
completers_mock["b"] = middle
completers_mock["c"] = non_exclusive_completer(lambda *a: {"c1", "c2"})
assert completer.complete("", "", 0, 0, {})[0] == exp