hermes-agent/tests/cli/test_cli_resume_command.py
Teknium 4fbdf0e893 test(cli,gateway): cover bracket-stripping and gateway session-ID lookup
- CLI: bracketed/quoted target resolves; mismatched single bracket passes through unchanged.
- Gateway: bracketed session ID resolves; bare untitled session ID resolves via get_session() fallback.
2026-05-25 01:33:32 -07:00

118 lines
4.8 KiB
Python

from unittest.mock import MagicMock, patch
from cli import HermesCLI
def _make_cli():
cli_obj = HermesCLI.__new__(HermesCLI)
cli_obj.session_id = "current_session"
cli_obj._resumed = False
cli_obj._pending_title = None
cli_obj.conversation_history = []
cli_obj.agent = None
cli_obj._session_db = MagicMock()
# _handle_resume_command now triggers _display_resumed_history (#31695),
# which reads self.resume_display. "minimal" short-circuits the recap so
# the test only exercises session-switch behavior.
cli_obj.resume_display = "minimal"
return cli_obj
class TestCliResumeCommand:
def test_show_recent_sessions_includes_indexes_and_resume_hint(self, capsys):
cli_obj = _make_cli()
cli_obj._list_recent_sessions = MagicMock(return_value=[
{"id": "sess_002", "title": "Coding", "preview": "build feature", "last_active": None},
{"id": "sess_001", "title": "Research", "preview": "read docs", "last_active": None},
])
shown = cli_obj._show_recent_sessions(reason="resume")
output = capsys.readouterr().out
assert shown is True
assert "1" in output
assert "2" in output
assert "Coding" in output
assert "Research" in output
assert "/resume 2" in output
assert "/resume <session title>" in output
def test_handle_resume_by_index_switches_to_numbered_session(self):
cli_obj = _make_cli()
cli_obj._list_recent_sessions = MagicMock(return_value=[
{"id": "sess_002", "title": "Coding"},
{"id": "sess_001", "title": "Research"},
])
cli_obj._session_db.get_session.return_value = {"id": "sess_001", "title": "Research"}
cli_obj._session_db.get_messages_as_conversation.return_value = [
{"role": "user", "content": "hello"},
{"role": "assistant", "content": "hi"},
]
# resolve_resume_session_id passes the id through when no compression chain.
cli_obj._session_db.resolve_resume_session_id.return_value = "sess_001"
with (
patch("hermes_cli.main._resolve_session_by_name_or_id", return_value=None),
patch("cli._cprint") as mock_cprint,
):
cli_obj._handle_resume_command("/resume 2")
printed = " ".join(str(call) for call in mock_cprint.call_args_list)
assert cli_obj.session_id == "sess_001"
assert "Resumed session sess_001" in printed
assert "Research" in printed
def test_handle_resume_by_index_out_of_range(self):
cli_obj = _make_cli()
cli_obj._list_recent_sessions = MagicMock(return_value=[
{"id": "sess_002", "title": "Coding"},
])
with patch("cli._cprint") as mock_cprint:
cli_obj._handle_resume_command("/resume 9")
printed = " ".join(str(call) for call in mock_cprint.call_args_list)
assert "out of range" in printed.lower()
assert "/resume" in printed
assert cli_obj.session_id == "current_session"
def test_handle_resume_strips_outer_brackets(self):
"""Users copy `<session_id>` from the usage hint literally.
Strip outer ``<>``, ``[]``, ``""``, and ``''`` before lookup so
``/resume <abc123>`` works the same as ``/resume abc123``.
"""
cli_obj = _make_cli()
cli_obj._session_db.get_session.return_value = {"id": "sess_alpha", "title": "Alpha"}
cli_obj._session_db.get_messages_as_conversation.return_value = []
cli_obj._session_db.resolve_resume_session_id.return_value = "sess_alpha"
for raw in ("<sess_alpha>", "[sess_alpha]", '"sess_alpha"', "'sess_alpha'"):
cli_obj.session_id = "current_session"
with (
patch("hermes_cli.main._resolve_session_by_name_or_id", return_value="sess_alpha"),
patch("cli._cprint"),
):
cli_obj._handle_resume_command(f"/resume {raw}")
assert cli_obj.session_id == "sess_alpha", (
f"bracket-stripping failed for {raw!r}: session_id stayed {cli_obj.session_id}"
)
def test_handle_resume_does_not_strip_partial_brackets(self):
"""Mismatched or single brackets must pass through unmodified.
``"<half`` (just an open angle) is not a wrapping pair, so the
lookup should treat it verbatim — preserving the existing
not-found error path instead of mangling the input.
"""
cli_obj = _make_cli()
cli_obj._session_db.get_session.return_value = None
with (
patch("hermes_cli.main._resolve_session_by_name_or_id", return_value=None),
patch("cli._cprint") as mock_cprint,
):
cli_obj._handle_resume_command("/resume <half")
printed = " ".join(str(call) for call in mock_cprint.call_args_list)
assert "<half" in printed