test: cover restart_claude_desktop() and profile_targets_claude_desktop() (#9)
Mocks subprocess.run/Popen and patches sys.platform per-OS branch (darwin, win32, linux) -- never actually kills or launches anything. Covers: correct command sequence per platform, pkill/taskkill exiting non-zero (nothing to kill) is NOT treated as failure, a failed relaunch IS reported as failure, and profile_targets_claude_desktop() correctly distinguishes Claude Desktop configs from Claude Code / legacy settings.json profiles.
This commit is contained in:
@@ -638,3 +638,159 @@ def test_args_secret_warning_env_not_triggered():
|
|||||||
def test_args_secret_warning_empty():
|
def test_args_secret_warning_empty():
|
||||||
assert c.args_secret_warning({}) is None
|
assert c.args_secret_warning({}) is None
|
||||||
assert c.args_secret_warning({"args": []}) is None
|
assert c.args_secret_warning({"args": []}) is None
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# restart_claude_desktop / profile_targets_claude_desktop (issue #9)
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
def test_profile_targets_claude_desktop_true_for_desktop_config():
|
||||||
|
p = c.Profile(label="Claude", path="/x/Claude/claude_desktop_config.json", config_exists=True)
|
||||||
|
assert c.profile_targets_claude_desktop(p)
|
||||||
|
|
||||||
|
|
||||||
|
def test_profile_targets_claude_desktop_false_for_claude_code():
|
||||||
|
p = c.Profile(label="Claude Code", path="/home/me/.claude.json", config_exists=True)
|
||||||
|
assert not c.profile_targets_claude_desktop(p)
|
||||||
|
|
||||||
|
|
||||||
|
def test_profile_targets_claude_desktop_false_for_legacy_settings():
|
||||||
|
p = c.Profile(
|
||||||
|
label="Claude Code (legacy settings.json)",
|
||||||
|
path="/home/me/.claude/settings.json",
|
||||||
|
config_exists=True,
|
||||||
|
)
|
||||||
|
assert not c.profile_targets_claude_desktop(p)
|
||||||
|
|
||||||
|
|
||||||
|
class _FakeCompletedProcess:
|
||||||
|
def __init__(self, returncode=0, stdout="", stderr=""):
|
||||||
|
self.returncode = returncode
|
||||||
|
self.stdout = stdout
|
||||||
|
self.stderr = stderr
|
||||||
|
|
||||||
|
|
||||||
|
def test_restart_claude_desktop_macos_commands(monkeypatch):
|
||||||
|
"""macOS: pkill -x "Claude" then open -a Claude, in that order."""
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
def fake_run(cmd, **kwargs):
|
||||||
|
calls.append(cmd)
|
||||||
|
return _FakeCompletedProcess(returncode=0)
|
||||||
|
|
||||||
|
monkeypatch.setattr(c.sys, "platform", "darwin")
|
||||||
|
monkeypatch.setattr(c.subprocess, "run", fake_run)
|
||||||
|
result = c.restart_claude_desktop()
|
||||||
|
assert result.success
|
||||||
|
assert calls[0] == ["pkill", "-x", "Claude"]
|
||||||
|
assert calls[1] == ["open", "-a", "Claude"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_restart_claude_desktop_macos_pkill_not_running_is_fine(monkeypatch):
|
||||||
|
"""pkill exiting non-zero (nothing to kill) must NOT be treated as failure."""
|
||||||
|
|
||||||
|
def fake_run(cmd, **kwargs):
|
||||||
|
if cmd[0] == "pkill":
|
||||||
|
return _FakeCompletedProcess(returncode=1) # no matching process
|
||||||
|
return _FakeCompletedProcess(returncode=0)
|
||||||
|
|
||||||
|
monkeypatch.setattr(c.sys, "platform", "darwin")
|
||||||
|
monkeypatch.setattr(c.subprocess, "run", fake_run)
|
||||||
|
result = c.restart_claude_desktop()
|
||||||
|
assert result.success
|
||||||
|
|
||||||
|
|
||||||
|
def test_restart_claude_desktop_macos_relaunch_failure_reported(monkeypatch):
|
||||||
|
def fake_run(cmd, **kwargs):
|
||||||
|
if cmd[0] == "open":
|
||||||
|
return _FakeCompletedProcess(returncode=1, stderr="Unable to find application")
|
||||||
|
return _FakeCompletedProcess(returncode=1)
|
||||||
|
|
||||||
|
monkeypatch.setattr(c.sys, "platform", "darwin")
|
||||||
|
monkeypatch.setattr(c.subprocess, "run", fake_run)
|
||||||
|
result = c.restart_claude_desktop()
|
||||||
|
assert not result.success
|
||||||
|
assert "Unable to find application" in result.detail
|
||||||
|
|
||||||
|
|
||||||
|
def test_restart_claude_desktop_macos_pkill_binary_missing_does_not_raise(monkeypatch):
|
||||||
|
"""pkill raising OSError (binary missing) must be swallowed, not propagated --
|
||||||
|
relaunch is still attempted."""
|
||||||
|
|
||||||
|
def fake_run(cmd, **kwargs):
|
||||||
|
if cmd[0] == "pkill":
|
||||||
|
raise OSError("pkill not found")
|
||||||
|
return _FakeCompletedProcess(returncode=0)
|
||||||
|
|
||||||
|
monkeypatch.setattr(c.sys, "platform", "darwin")
|
||||||
|
monkeypatch.setattr(c.subprocess, "run", fake_run)
|
||||||
|
result = c.restart_claude_desktop()
|
||||||
|
assert result.success
|
||||||
|
|
||||||
|
|
||||||
|
def test_restart_claude_desktop_windows_commands(monkeypatch):
|
||||||
|
"""Windows: taskkill the process, then relaunch via the Start-menu shortcut."""
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
def fake_run(cmd, **kwargs):
|
||||||
|
calls.append(cmd)
|
||||||
|
return _FakeCompletedProcess(returncode=0)
|
||||||
|
|
||||||
|
monkeypatch.setattr(c.sys, "platform", "win32")
|
||||||
|
monkeypatch.setattr(c.subprocess, "run", fake_run)
|
||||||
|
result = c.restart_claude_desktop()
|
||||||
|
assert result.success
|
||||||
|
assert calls[0] == ["taskkill", "/IM", "Claude.exe", "/F"]
|
||||||
|
assert calls[1][:3] == ["cmd", "/c", "start"]
|
||||||
|
assert calls[1][-1].endswith("Claude.lnk")
|
||||||
|
|
||||||
|
|
||||||
|
def test_restart_claude_desktop_windows_relaunch_failure_reported(monkeypatch):
|
||||||
|
def fake_run(cmd, **kwargs):
|
||||||
|
if cmd[0] == "cmd":
|
||||||
|
return _FakeCompletedProcess(returncode=1, stderr="not found")
|
||||||
|
return _FakeCompletedProcess(returncode=0)
|
||||||
|
|
||||||
|
monkeypatch.setattr(c.sys, "platform", "win32")
|
||||||
|
monkeypatch.setattr(c.subprocess, "run", fake_run)
|
||||||
|
result = c.restart_claude_desktop()
|
||||||
|
assert not result.success
|
||||||
|
assert "not found" in result.detail
|
||||||
|
|
||||||
|
|
||||||
|
def test_restart_claude_desktop_linux_commands(monkeypatch):
|
||||||
|
"""Linux: pkill claude, then relaunch via a detached Popen (no waiting)."""
|
||||||
|
run_calls = []
|
||||||
|
popen_calls = []
|
||||||
|
|
||||||
|
def fake_run(cmd, **kwargs):
|
||||||
|
run_calls.append(cmd)
|
||||||
|
return _FakeCompletedProcess(returncode=0)
|
||||||
|
|
||||||
|
class _FakePopen:
|
||||||
|
def __init__(self, cmd, **kwargs):
|
||||||
|
popen_calls.append((cmd, kwargs))
|
||||||
|
|
||||||
|
monkeypatch.setattr(c.sys, "platform", "linux")
|
||||||
|
monkeypatch.setattr(c.subprocess, "run", fake_run)
|
||||||
|
monkeypatch.setattr(c.subprocess, "Popen", _FakePopen)
|
||||||
|
result = c.restart_claude_desktop()
|
||||||
|
assert result.success
|
||||||
|
assert run_calls == [["pkill", "claude"]]
|
||||||
|
cmd, kwargs = popen_calls[0]
|
||||||
|
assert cmd == ["claude"]
|
||||||
|
assert kwargs.get("start_new_session") is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_restart_claude_desktop_linux_popen_failure_reported(monkeypatch):
|
||||||
|
def fake_run(cmd, **kwargs):
|
||||||
|
return _FakeCompletedProcess(returncode=0)
|
||||||
|
|
||||||
|
def fake_popen(cmd, **kwargs):
|
||||||
|
raise OSError("no such file or directory")
|
||||||
|
|
||||||
|
monkeypatch.setattr(c.sys, "platform", "linux")
|
||||||
|
monkeypatch.setattr(c.subprocess, "run", fake_run)
|
||||||
|
monkeypatch.setattr(c.subprocess, "Popen", fake_popen)
|
||||||
|
result = c.restart_claude_desktop()
|
||||||
|
assert not result.success
|
||||||
|
assert "Claude Desktop" in result.detail
|
||||||
|
|||||||
Reference in New Issue
Block a user