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
168 lines
6.0 KiB
Python
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"]
|