Spaces:
Paused
Paused
File size: 6,131 Bytes
b5b9c2e | 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 | """Tests for /tools slash command handler in the interactive CLI."""
from unittest.mock import MagicMock, patch, call
from cli import HermesCLI
def _make_cli(enabled_toolsets=None):
"""Build a minimal HermesCLI stub without running __init__."""
cli_obj = HermesCLI.__new__(HermesCLI)
cli_obj.enabled_toolsets = set(enabled_toolsets or ["web", "memory"])
cli_obj._command_running = False
cli_obj.console = MagicMock()
return cli_obj
# ── /tools (no subcommand) ──────────────────────────────────────────────────
class TestToolsSlashNoSubcommand:
def test_bare_tools_shows_tool_list(self):
cli_obj = _make_cli()
with patch.object(cli_obj, "show_tools") as mock_show:
cli_obj._handle_tools_command("/tools")
mock_show.assert_called_once()
def test_unknown_subcommand_falls_back_to_show_tools(self):
cli_obj = _make_cli()
with patch.object(cli_obj, "show_tools") as mock_show:
cli_obj._handle_tools_command("/tools foobar")
mock_show.assert_called_once()
# ── /tools list ─────────────────────────────────────────────────────────────
class TestToolsSlashList:
def test_list_calls_backend(self, capsys):
cli_obj = _make_cli()
with patch("hermes_cli.tools_config.load_config",
return_value={"platform_toolsets": {"cli": ["web"]}}), \
patch("hermes_cli.tools_config.save_config"):
cli_obj._handle_tools_command("/tools list")
out = capsys.readouterr().out
assert "web" in out
def test_list_does_not_modify_enabled_toolsets(self):
"""List is read-only — self.enabled_toolsets must not change."""
cli_obj = _make_cli(["web", "memory"])
with patch("hermes_cli.tools_config.load_config",
return_value={"platform_toolsets": {"cli": ["web"]}}):
cli_obj._handle_tools_command("/tools list")
assert cli_obj.enabled_toolsets == {"web", "memory"}
# ── /tools disable (session reset) ──────────────────────────────────────────
class TestToolsSlashDisableWithReset:
def test_disable_applies_directly_and_resets_session(self):
"""Disable applies immediately (no confirmation prompt) and resets session."""
cli_obj = _make_cli(["web", "memory"])
with patch("hermes_cli.tools_config.load_config",
return_value={"platform_toolsets": {"cli": ["web", "memory"]}}), \
patch("hermes_cli.tools_config.save_config"), \
patch("hermes_cli.tools_config._get_platform_tools", return_value={"memory"}), \
patch("hermes_cli.config.load_config", return_value={}), \
patch.object(cli_obj, "new_session") as mock_reset:
cli_obj._handle_tools_command("/tools disable web")
mock_reset.assert_called_once()
assert "web" not in cli_obj.enabled_toolsets
def test_disable_does_not_prompt_for_confirmation(self):
"""Disable no longer uses input() — it applies directly."""
cli_obj = _make_cli(["web", "memory"])
with patch("hermes_cli.tools_config.load_config",
return_value={"platform_toolsets": {"cli": ["web", "memory"]}}), \
patch("hermes_cli.tools_config.save_config"), \
patch("hermes_cli.tools_config._get_platform_tools", return_value={"memory"}), \
patch("hermes_cli.config.load_config", return_value={}), \
patch.object(cli_obj, "new_session"), \
patch("builtins.input") as mock_input:
cli_obj._handle_tools_command("/tools disable web")
mock_input.assert_not_called()
def test_disable_always_resets_session(self):
"""Even without a confirmation prompt, disable always resets the session."""
cli_obj = _make_cli(["web", "memory"])
with patch("hermes_cli.tools_config.load_config",
return_value={"platform_toolsets": {"cli": ["web", "memory"]}}), \
patch("hermes_cli.tools_config.save_config"), \
patch("hermes_cli.tools_config._get_platform_tools", return_value={"memory"}), \
patch("hermes_cli.config.load_config", return_value={}), \
patch.object(cli_obj, "new_session") as mock_reset:
cli_obj._handle_tools_command("/tools disable web")
mock_reset.assert_called_once()
def test_disable_missing_name_prints_usage(self, capsys):
cli_obj = _make_cli()
cli_obj._handle_tools_command("/tools disable")
out = capsys.readouterr().out
assert "Usage" in out
# ── /tools enable (session reset) ───────────────────────────────────────────
class TestToolsSlashEnableWithReset:
def test_enable_applies_directly_and_resets_session(self):
"""Enable applies immediately (no confirmation prompt) and resets session."""
cli_obj = _make_cli(["memory"])
with patch("hermes_cli.tools_config.load_config",
return_value={"platform_toolsets": {"cli": ["memory"]}}), \
patch("hermes_cli.tools_config.save_config"), \
patch("hermes_cli.tools_config._get_platform_tools", return_value={"memory", "web"}), \
patch("hermes_cli.config.load_config", return_value={}), \
patch.object(cli_obj, "new_session") as mock_reset:
cli_obj._handle_tools_command("/tools enable web")
mock_reset.assert_called_once()
assert "web" in cli_obj.enabled_toolsets
def test_enable_missing_name_prints_usage(self, capsys):
cli_obj = _make_cli()
cli_obj._handle_tools_command("/tools enable")
out = capsys.readouterr().out
assert "Usage" in out
|