Files
EvoScientist-Multi/tests/test_command_completions.py
Wiktor Cupiał 1d117ff277 feat: completion enchancements (#302)
* feat: completion enchancements

* fix: handle exception

* fix: duplicate view

* fix: remove deadcode

* fix tab
2026-07-05 05:14:42 +00:00

131 lines
4.4 KiB
Python

"""Tests for multi-stage command completions, categories, and dynamic completions."""
from unittest.mock import patch
from EvoScientist.commands._completion_engine import compute_completions
class TestTopLevelCompletions:
def test_slash_returns_all_commands(self):
r = compute_completions("/", 1)
names = [c.text for c in r.candidates]
assert "/mcp" in names
assert "/help" in names
assert "/new" in names
def test_prefix_filters(self):
r = compute_completions("/mc", 3)
names = [c.text for c in r.candidates]
assert "/mcp" in names
assert "/help" not in names
def test_exact_leaf_hides(self):
r = compute_completions("/new", 4)
assert r.kind == "empty"
def test_exact_with_subcommands_hides_without_space(self):
r = compute_completions("/mcp", 4)
assert r.kind == "empty"
def test_results_have_categories(self):
r = compute_completions("/", 1)
cats = {c.category for c in r.candidates}
assert "Session" in cats
assert "MCP" in cats
assert "General" in cats
def test_category_ordering(self):
r = compute_completions("/", 1)
cats = []
for c in r.candidates:
if not cats or cats[-1] != c.category:
cats.append(c.category)
assert cats.index("Session") < cats.index("General")
class TestAliasVisibility:
def test_alias_prefix_matches(self):
r = compute_completions("/fa", 3)
names = [c.text for c in r.candidates]
assert "/model-fallback" in names
def test_alias_exact_hides_leaf(self):
r = compute_completions("/quit", 5)
assert r.kind == "empty"
def test_alias_exact_hides_without_space(self):
r = compute_completions("/fallback", 9)
assert r.kind == "empty"
def test_alias_space_shows_subcommands(self):
r = compute_completions("/fallback ", 10)
names = [c.text for c in r.candidates]
assert "add" in names
assert "list" in names
class TestSubcommandCompletions:
def test_space_shows_subcommands(self):
r = compute_completions("/mcp ", 5)
names = [c.text for c in r.candidates]
assert "list" in names
assert "config" in names
assert "install" in names
def test_prefix_filters_subcommands(self):
r = compute_completions("/mcp c", 6)
names = [c.text for c in r.candidates]
assert "config" in names
assert "list" not in names
def test_leaf_subcommand_stops(self):
r = compute_completions("/model-fallback help ", 21)
assert r.kind == "empty"
def test_channel_all_types(self):
r = compute_completions("/channel ", 9)
names = [c.text for c in r.candidates]
assert "status" in names
assert "telegram" in names
assert "discord" in names
def test_model_fallback_subcommands(self):
r = compute_completions("/model-fallback ", 16)
names = [c.text for c in r.candidates]
assert "add" in names
assert "clear" in names
class TestDynamicCompletions:
def _invalidate_mcp_cache(self):
from EvoScientist.commands.implementation.mcp import MCPCommand
from EvoScientist.commands.manager import manager
cmd = manager.get_command("/mcp")
if isinstance(cmd, MCPCommand):
cmd._invalidate_server_cache()
def test_mcp_config_server_names(self):
self._invalidate_mcp_cache()
fake_config = {"myserver": {}, "other": {}}
with patch("EvoScientist.mcp.load_mcp_config", return_value=fake_config):
r = compute_completions("/mcp config ", 12)
names = [c.text for c in r.candidates]
assert "myserver" in names
assert "other" in names
def test_mcp_config_prefix_filters(self):
self._invalidate_mcp_cache()
fake_config = {"myserver": {}, "other": {}}
with patch("EvoScientist.mcp.load_mcp_config", return_value=fake_config):
r = compute_completions("/mcp config my", 14)
names = [c.text for c in r.candidates]
assert names == ["myserver"]
def test_mcp_remove_shows_servers(self):
self._invalidate_mcp_cache()
fake_config = {"srv1": {}}
with patch("EvoScientist.mcp.load_mcp_config", return_value=fake_config):
r = compute_completions("/mcp remove ", 12)
assert [c.text for c in r.candidates] == ["srv1"]