Files
wehub-resource-sync f3d80b4628
Auto Release / auto-release (push) Failing after 1s
CI / lint (push) Failing after 0s
CI / screenshot-quality (push) Failing after 3s
CI / pr-policy (push) Has been skipped
CI / test (3.11) (push) Failing after 0s
CI / test (3.12) (push) Failing after 0s
CI / test (3.13) (push) Failing after 3s
CI / coverage (push) Failing after 1s
Legibility / legibility (push) Failing after 3s
chore: import upstream snapshot with attribution
2026-07-13 12:31:48 +08:00

168 lines
6.0 KiB
Python

from __future__ import annotations
import subprocess
import sys
import pytest
from claude_tap.cli import (
_build_update_command,
_detect_installer,
main_entry,
parse_update_args,
update_main,
)
def test_detect_installer_uses_uv_tool_environment(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
"claude_tap.cli_update.sys.executable",
r"C:\Users\alice\AppData\Roaming\uv\data\tools\claude-tap\Scripts\python.exe",
)
monkeypatch.setattr("claude_tap.cli_update.sys.platform", "win32")
monkeypatch.setattr("claude_tap.cli_update.shutil.which", lambda _name: r"C:\tools\uv.exe")
assert _detect_installer() == "uv"
def test_detect_installer_honors_custom_uv_tool_dir(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(
"claude_tap.cli_update.sys.executable",
r"D:\managed-tools\claude-tap\Scripts\python.exe",
)
monkeypatch.setenv("UV_TOOL_DIR", r"D:\managed-tools")
monkeypatch.setattr("claude_tap.cli_update.sys.platform", "win32")
monkeypatch.setattr("claude_tap.cli_update.shutil.which", lambda _name: None)
assert _detect_installer() == "uv"
def test_detect_installer_does_not_treat_uv_on_path_as_windows_uv_install(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr("claude_tap.cli_update.sys.executable", r"C:\Python312\python.exe")
monkeypatch.setattr("claude_tap.cli_update.sys.platform", "win32")
monkeypatch.setattr("claude_tap.cli_update.shutil.which", lambda _name: r"C:\tools\uv.exe")
assert _detect_installer() == "pip"
def test_detect_installer_keeps_non_windows_uv_path_fallback(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr("claude_tap.cli_update.sys.executable", "/usr/bin/python3")
monkeypatch.setattr("claude_tap.cli_update.sys.platform", "linux")
monkeypatch.setattr("claude_tap.cli_update.shutil.which", lambda _name: "/usr/bin/uv")
assert _detect_installer() == "uv"
def test_build_update_command_uses_uv_shim(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr("claude_tap.cli.shutil.which", lambda name: "/tmp/uv" if name == "uv" else None)
assert _build_update_command("uv") == ["/tmp/uv", "tool", "upgrade", "claude-tap"]
def test_build_update_command_returns_none_when_uv_missing(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr("claude_tap.cli.shutil.which", lambda _name: None)
assert _build_update_command("uv") is None
def test_build_update_command_uses_current_python_for_pip() -> None:
assert _build_update_command("pip") == [sys.executable, "-m", "pip", "install", "--upgrade", "claude-tap"]
def test_parse_update_args_defaults_to_auto() -> None:
args = parse_update_args([])
assert args.installer == "auto"
assert args.dry_run is False
def test_update_main_dry_run_prints_command(
monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
) -> None:
monkeypatch.setattr("claude_tap.cli.shutil.which", lambda name: "/tmp/uv" if name == "uv" else None)
assert update_main(["--installer", "uv", "--dry-run"]) == 0
out = capsys.readouterr().out
assert "Upgrading claude-tap with uv" in out
assert "/tmp/uv tool upgrade claude-tap" in out
def test_update_main_runs_selected_command(monkeypatch: pytest.MonkeyPatch) -> None:
captured: dict[str, object] = {}
def fake_run(cmd, **kwargs):
captured["cmd"] = cmd
captured["kwargs"] = kwargs
return subprocess.CompletedProcess(cmd, 7)
monkeypatch.setattr(subprocess, "run", fake_run)
assert update_main(["--installer", "pip"]) == 7
assert captured["cmd"] == [sys.executable, "-m", "pip", "install", "--upgrade", "claude-tap"]
assert captured["kwargs"] == {"check": False}
def test_update_main_hides_windows_console(monkeypatch: pytest.MonkeyPatch) -> None:
captured: dict[str, object] = {}
class FakeStartupInfo:
def __init__(self) -> None:
self.dwFlags = 0
self.wShowWindow: int | None = None
def fake_run(cmd, **kwargs):
captured["cmd"] = cmd
captured["kwargs"] = kwargs
return subprocess.CompletedProcess(cmd, 0)
monkeypatch.setattr("claude_tap.cli_update.sys.platform", "win32")
monkeypatch.setattr(subprocess, "run", fake_run)
monkeypatch.setattr(subprocess, "CREATE_NO_WINDOW", 0x1000, raising=False)
monkeypatch.setattr(subprocess, "CREATE_NEW_PROCESS_GROUP", 0x2000, raising=False)
monkeypatch.setattr(subprocess, "STARTF_USESHOWWINDOW", 0x4000, raising=False)
monkeypatch.setattr(subprocess, "SW_HIDE", 0, raising=False)
monkeypatch.setattr(subprocess, "STARTUPINFO", FakeStartupInfo, raising=False)
assert update_main(["--installer", "pip"]) == 0
assert captured["cmd"] == [sys.executable, "-m", "pip", "install", "--upgrade", "claude-tap"]
kwargs = captured["kwargs"]
assert isinstance(kwargs, dict)
assert kwargs["check"] is False
assert kwargs["stdin"] == subprocess.DEVNULL
assert kwargs["creationflags"] == 0x1000 | 0x2000
startupinfo = kwargs["startupinfo"]
assert isinstance(startupinfo, FakeStartupInfo)
assert startupinfo.dwFlags == 0x4000
assert startupinfo.wShowWindow == 0
def test_update_main_reports_missing_uv(monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]) -> None:
monkeypatch.setattr("claude_tap.cli.shutil.which", lambda _name: None)
assert update_main(["--installer", "uv"]) == 1
err = capsys.readouterr().err
assert "uv" in err
assert "--installer pip" in err
def test_main_entry_routes_update_subcommand(monkeypatch: pytest.MonkeyPatch) -> None:
called: dict[str, object] = {}
def fake_update_main(argv):
called["argv"] = argv
return 3
monkeypatch.setattr(sys, "argv", ["claude-tap", "update", "--installer", "pip"])
monkeypatch.setattr("claude_tap.cli.update_main", fake_update_main)
with pytest.raises(SystemExit) as excinfo:
main_entry()
assert excinfo.value.code == 3
assert called["argv"] == ["--installer", "pip"]