hermes-agent/tests/hermes_cli/test_banner.py
Jeff Watts 53f7d137ed fix(windows): native Windows correctness for CLI, gateway status, banner, and WSL browser paths
Salvaged from #57016 by @lEWFkRAD:
- cli.py: handle file:///C:/... drive-letter URIs on nt (strip the
  leading slash urlparse leaves); join Termux example paths with literal
  forward slashes so hints stay POSIX on Windows.
- gateway/status.py + hermes_cli/gateway.py: normalize backslashes to
  forward slashes before the HERMES_HOME substring match so separator
  style cannot defeat profile ownership detection.
- hermes_cli/banner.py: cprint degrades to plain print when
  prompt_toolkit has no console (NoConsoleScreenBufferError on
  redirected/absent Windows stdout).
- hermes_cli/browser_connect.py: posixpath.join for WSL /mnt/c/... bases
  (os.path.join would emit backslashes on nt).
- Test hardening: symlink skip-guards, USERPROFILE alongside HOME for
  ntpath.expanduser, SIGKILL absence skipif fixed via monkeypatch,
  drive-letter URI / separator-normalization / banner-fallback coverage.

Dropped from the original PR: tests/cli/conftest.py fixture and the
AppSession _output monkeypatch — main's merged tests/cli/conftest.py
already handles that prompt_toolkit pollution.
2026-07-29 23:16:18 -07:00

85 lines
2.8 KiB
Python

"""Tests for banner toolset name normalization and skin color usage."""
from unittest.mock import patch
from rich.console import Console
import hermes_cli.banner as banner
import model_tools
import tools.mcp_tool
def test_cprint_falls_back_to_plain_print_when_prompt_toolkit_has_no_console(capsys):
with patch(
"prompt_toolkit.print_formatted_text",
side_effect=RuntimeError("no console screen buffer"),
):
banner.cprint("fallback text")
assert capsys.readouterr().out == "fallback text\n"
def test_build_welcome_banner_title_falls_back_when_no_tag():
"""Without a resolvable tag, the panel title renders as plain text (no hyperlink escape)."""
import io
from unittest.mock import patch as _patch
import hermes_cli.banner as _banner
import model_tools as _mt
import tools.mcp_tool as _mcp
_banner._latest_release_cache = None
buf = io.StringIO()
with (
_patch.object(_mt, "check_tool_availability", return_value=(["web"], [])),
_patch.object(_banner, "get_available_skills", return_value={}),
_patch.object(_banner, "get_update_result", return_value=None),
_patch.object(_mcp, "get_mcp_status", return_value=[]),
_patch.object(_banner, "get_latest_release_tag", return_value=None),
):
console = Console(file=buf, force_terminal=True, color_system="truecolor", width=160)
_banner.build_welcome_banner(
console=console, model="x", cwd="/tmp",
session_id="abc123",
tools=[{"function": {"name": "read_file"}}],
get_toolset_for_tool=lambda n: "file",
)
raw = buf.getvalue()
assert "Hermes Agent v" in raw, "Version label missing from title"
assert "\x1b]8;" not in raw, "OSC-8 hyperlink should not be emitted without a tag"
def test_build_welcome_banner_non_moa_unchanged(tmp_path, monkeypatch):
"""A normal provider still renders the bare model slug, no MoA prefix."""
monkeypatch.setenv("HERMES_HOME", str(tmp_path / ".hermes"))
(tmp_path / ".hermes").mkdir()
with (
patch.object(model_tools, "check_tool_availability", return_value=([], [])),
patch.object(banner, "get_available_skills", return_value={}),
patch.object(banner, "get_update_result", return_value=None),
patch.object(tools.mcp_tool, "get_mcp_status", return_value=[]),
):
console = Console(record=True, force_terminal=False, color_system=None, width=160)
banner.build_welcome_banner(
console=console,
model="anthropic/claude-opus-4.8",
cwd="/tmp/project",
tools=[],
enabled_toolsets=[],
provider="openrouter",
)
out = console.export_text()
assert "claude-opus-4.8" in out
assert "MoA:" not in out