Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
"""Tests for ``remove_path_from_shell_configs`` — the uninstaller's shell-rc rewrite.
|
||||
|
||||
This rewrites files Hermes does not own (``~/.bashrc``, ``~/.zshrc``, ...) and
|
||||
takes no backup of them, so the rewrite has to be atomic: a bare
|
||||
``write_text()`` truncates the rc file before the new content lands, and the
|
||||
caller wraps everything in ``except Exception: log_warn(...)``, so a partial
|
||||
write is downgraded to a warning and the user's next login starts a bare shell.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from hermes_cli import uninstall
|
||||
|
||||
|
||||
ZSHRC = (
|
||||
"export EDITOR=vim\n"
|
||||
"alias ll='ls -la'\n"
|
||||
"\n"
|
||||
"# Hermes Agent\n"
|
||||
'export PATH="$HOME/.local/bin:$PATH"\n'
|
||||
"\n"
|
||||
"source ~/.work-profile\n"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_home(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
|
||||
"""Point both ``Path.home()`` and ``HERMES_HOME`` at a throwaway dir."""
|
||||
home = tmp_path / "home"
|
||||
home.mkdir()
|
||||
monkeypatch.setattr(Path, "home", classmethod(lambda cls: home))
|
||||
monkeypatch.setenv("HERMES_HOME", str(home / ".hermes"))
|
||||
return home
|
||||
|
||||
|
||||
class TestHappyPath:
|
||||
def test_hermes_path_block_is_removed(self, fake_home: Path):
|
||||
rc = fake_home / ".zshrc"
|
||||
rc.write_text(ZSHRC, encoding="utf-8")
|
||||
|
||||
removed = uninstall.remove_path_from_shell_configs()
|
||||
|
||||
assert removed == [rc]
|
||||
text = rc.read_text(encoding="utf-8")
|
||||
assert "# Hermes Agent" not in text
|
||||
# The user's own lines are untouched.
|
||||
assert "export EDITOR=vim" in text
|
||||
assert "source ~/.work-profile" in text
|
||||
|
||||
def test_untouched_rc_is_not_reported(self, fake_home: Path):
|
||||
rc = fake_home / ".zshrc"
|
||||
rc.write_text("export EDITOR=vim\n", encoding="utf-8")
|
||||
|
||||
assert uninstall.remove_path_from_shell_configs() == []
|
||||
assert rc.read_text(encoding="utf-8") == "export EDITOR=vim\n"
|
||||
|
||||
|
||||
class TestCrashDurability:
|
||||
def test_shell_config_survives_an_interrupted_rewrite(self, fake_home: Path):
|
||||
"""An interrupted rewrite must leave the rc file byte-identical.
|
||||
|
||||
There is no backup of the user's shell rc anywhere in this code path,
|
||||
so a truncated write is unrecoverable.
|
||||
"""
|
||||
rc = fake_home / ".zshrc"
|
||||
rc.write_text(ZSHRC, encoding="utf-8")
|
||||
original = rc.read_bytes()
|
||||
|
||||
def boom(fd):
|
||||
raise OSError("simulated crash mid-write")
|
||||
|
||||
# Scoped context so restoring os.fsync doesn't also undo the
|
||||
# Path.home()/HERMES_HOME patches the fake_home fixture installed.
|
||||
with pytest.MonkeyPatch.context() as mp:
|
||||
mp.setattr(os, "fsync", boom)
|
||||
removed = uninstall.remove_path_from_shell_configs()
|
||||
|
||||
# The write failed, so the rc must not be reported as modified...
|
||||
assert removed == []
|
||||
# ...and it must still be exactly what the user had.
|
||||
assert rc.read_bytes() == original
|
||||
# The aborted write must not leave a temp file behind in $HOME.
|
||||
assert list(fake_home.glob("*.tmp")) == []
|
||||
|
||||
def test_symlinked_shell_config_stays_a_symlink(self, fake_home: Path):
|
||||
"""A dotfiles-repo ``~/.zshrc`` is a symlink; replacing it with a
|
||||
regular file silently detaches the user's dotfiles."""
|
||||
dotfiles = fake_home / "dotfiles"
|
||||
dotfiles.mkdir()
|
||||
real = dotfiles / "zshrc"
|
||||
real.write_text(ZSHRC, encoding="utf-8")
|
||||
rc = fake_home / ".zshrc"
|
||||
rc.symlink_to(real)
|
||||
|
||||
removed = uninstall.remove_path_from_shell_configs()
|
||||
|
||||
assert removed == [rc]
|
||||
assert rc.is_symlink(), "the symlink was replaced by a regular file"
|
||||
assert "# Hermes Agent" not in real.read_text(encoding="utf-8")
|
||||
assert "export EDITOR=vim" in real.read_text(encoding="utf-8")
|
||||
|
||||
@pytest.mark.skipif(sys.platform == "win32", reason="POSIX permission bits")
|
||||
def test_existing_file_mode_is_preserved(self, fake_home: Path):
|
||||
"""Shell rc files are normally 0644; uninstalling must not change that."""
|
||||
rc = fake_home / ".zshrc"
|
||||
rc.write_text(ZSHRC, encoding="utf-8")
|
||||
os.chmod(rc, 0o644)
|
||||
|
||||
uninstall.remove_path_from_shell_configs()
|
||||
|
||||
mode = stat.S_IMODE(rc.stat().st_mode)
|
||||
assert mode == 0o644, f"mode changed to {oct(mode)}"
|
||||
Reference in New Issue
Block a user