import subprocess from types import SimpleNamespace def test_browse_sh_availability_reports_missing_cli(monkeypatch): from services import browse_sh_tool from services.browse_sh_tool import BrowseShTool monkeypatch.delenv("BROWSE_SH_CLI", raising=False) monkeypatch.setattr(browse_sh_tool.shutil, "which", lambda _name: None) availability = BrowseShTool().availability() assert availability.available is False assert availability.command == tuple() assert "未安裝" in availability.reason def test_browse_sh_build_command_prefers_env_override(monkeypatch): from services import browse_sh_tool from services.browse_sh_tool import BrowseShTool monkeypatch.setenv("BROWSE_SH_CLI", "/opt/bin/browse") monkeypatch.setattr(browse_sh_tool.shutil, "which", lambda _name: "/usr/local/bin/browse") assert BrowseShTool().build_command(("skills", "list")) == ( "/opt/bin/browse", "skills", "list", ) def test_browse_sh_run_returns_success(monkeypatch): from services.browse_sh_tool import BrowseShTool calls = [] def fake_run(command, **kwargs): calls.append((command, kwargs)) return SimpleNamespace(returncode=0, stdout="ok", stderr="") monkeypatch.setattr("services.browse_sh_tool.subprocess.run", fake_run) result = BrowseShTool(cli_path="/bin/browse").run(("skills", "list"), require_available=False) assert result.ok is True assert result.command == ("/bin/browse", "skills", "list") assert result.stdout == "ok" assert calls[0][0] == ("/bin/browse", "skills", "list") def test_browse_sh_run_converts_timeout(monkeypatch): from services.browse_sh_tool import BrowseShTool def fake_run(command, **_kwargs): raise subprocess.TimeoutExpired(command, timeout=1, output="partial", stderr="late") monkeypatch.setattr("services.browse_sh_tool.subprocess.run", fake_run) result = BrowseShTool(cli_path="/bin/browse").run(("screenshot",), require_available=False) assert result.ok is False assert result.timed_out is True assert result.stdout == "partial" assert result.stderr == "late" def test_browse_sh_run_surfaces_broken_cli(monkeypatch): from services.browse_sh_tool import BrowseShTool def fake_run(command, **kwargs): if command[-1] == "--version": return SimpleNamespace(returncode=1, stdout="", stderr="node dyld missing icu4c") return SimpleNamespace(returncode=0, stdout="", stderr="") monkeypatch.setattr("services.browse_sh_tool.subprocess.run", fake_run) result = BrowseShTool(cli_path="/bin/browse").run(("skills", "list")) assert result.ok is False assert "icu4c" in result.unavailable_reason