gabriel / muse public
test_cmd_symlog_prune_orphans.py python
131 lines 4.6 KB
Raw
sha256:8fff16f1bc41d40757bb7488701ddbc520adbed1effb6429da72f06b84631e56 feat(format-patch,rev-list): -N shorthand + A..B range pari… Sonnet 5 patch 22 minutes ago
1 """muse#53 item 12 -- `muse symlog prune-orphans [--dry-run] [--json]`.
2
3 Finds and removes symlog journals whose symbol no longer exists at HEAD
4 (file deleted, or symbol removed from a file that still exists).
5 """
6
7 from __future__ import annotations
8
9 import json
10 import os
11 import pathlib
12 import textwrap
13
14 from tests.cli_test_helper import CliRunner
15
16 runner = CliRunner()
17
18
19 def _invoke(repo: pathlib.Path, args: list[str]):
20 saved = os.getcwd()
21 try:
22 os.chdir(repo)
23 return runner.invoke(None, args)
24 finally:
25 os.chdir(saved)
26
27
28 def _init_repo(repo: pathlib.Path) -> None:
29 repo.mkdir(parents=True, exist_ok=True)
30 _invoke(repo, ["init"])
31
32
33 def _write_file(repo: pathlib.Path, rel: str, content: str) -> None:
34 p = repo / rel
35 p.parent.mkdir(parents=True, exist_ok=True)
36 p.write_text(textwrap.dedent(content))
37
38
39 def _commit(repo: pathlib.Path, msg: str) -> str:
40 _invoke(repo, ["code", "add", "."])
41 result = _invoke(repo, [
42 "commit", "-m", msg,
43 "--agent-id", "claude-code",
44 "--model-id", "claude-sonnet-4-6",
45 "--author", "claude-code",
46 "--json",
47 ])
48 data = json.loads(result.stdout)
49 return data["commit_id"]
50
51
52 def _make_repo(tmp_path: pathlib.Path) -> pathlib.Path:
53 _init_repo(tmp_path)
54 return tmp_path
55
56
57 def _symlog(repo: pathlib.Path, *args: str):
58 return _invoke(repo, ["symlog", *args])
59
60
61 class TestPruneOrphans:
62 def test_no_orphans_in_clean_repo(self, tmp_path: pathlib.Path) -> None:
63 repo = _make_repo(tmp_path)
64 _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items)\n")
65 _commit(repo, "add compute_total")
66
67 result = _symlog(repo, "prune-orphans", "--json")
68 assert result.exit_code == 0, result.stdout
69 data = json.loads(result.stdout)
70 assert data["pruned"] == 0
71 assert data["symbols"] == []
72
73 # The live symbol's journal must still exist afterward.
74 exists_result = _symlog(repo, "exists", "src/billing.py::compute_total")
75 assert exists_result.exit_code == 0
76
77 def test_orphan_from_deleted_symbol_is_pruned(self, tmp_path: pathlib.Path) -> None:
78 repo = _make_repo(tmp_path)
79 _write_file(repo, "src/billing.py", (
80 "def compute_total(items):\n return sum(items)\n\n"
81 "def apply_discount(total, pct):\n return total * (1 - pct)\n"
82 ))
83 _commit(repo, "add two functions")
84 # Remove apply_discount entirely.
85 _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items)\n")
86 _commit(repo, "remove apply_discount")
87
88 result = _symlog(repo, "prune-orphans", "--json")
89 assert result.exit_code == 0, result.stdout
90 data = json.loads(result.stdout)
91 assert data["pruned"] == 1
92 assert data["symbols"] == ["src/billing.py::apply_discount"]
93
94 # Surviving symbol's journal must be untouched.
95 exists_result = _symlog(repo, "exists", "src/billing.py::compute_total")
96 assert exists_result.exit_code == 0
97 # Orphaned symbol's journal must now be gone.
98 orphan_exists = _symlog(repo, "exists", "src/billing.py::apply_discount")
99 assert orphan_exists.exit_code == 1
100
101 def test_orphan_from_deleted_file_is_pruned(self, tmp_path: pathlib.Path) -> None:
102 repo = _make_repo(tmp_path)
103 _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items)\n")
104 _commit(repo, "add compute_total")
105 (repo / "src" / "billing.py").unlink()
106 _invoke(repo, ["rm", "src/billing.py"])
107 _commit(repo, "remove billing.py")
108
109 result = _symlog(repo, "prune-orphans", "--json")
110 data = json.loads(result.stdout)
111 assert data["pruned"] == 1
112 assert data["symbols"] == ["src/billing.py::compute_total"]
113
114 def test_dry_run_does_not_delete(self, tmp_path: pathlib.Path) -> None:
115 repo = _make_repo(tmp_path)
116 _write_file(repo, "src/billing.py", (
117 "def compute_total(items):\n return sum(items)\n\n"
118 "def apply_discount(total, pct):\n return total * (1 - pct)\n"
119 ))
120 _commit(repo, "add two functions")
121 _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items)\n")
122 _commit(repo, "remove apply_discount")
123
124 result = _symlog(repo, "prune-orphans", "--dry-run", "--json")
125 data = json.loads(result.stdout)
126 assert data["pruned"] == 1
127 assert data["dry_run"] is True
128
129 # Still present after a dry-run.
130 still_there = _symlog(repo, "exists", "src/billing.py::apply_discount")
131 assert still_there.exit_code == 0
File History 1 commit
sha256:8fff16f1bc41d40757bb7488701ddbc520adbed1effb6429da72f06b84631e56 feat(format-patch,rev-list): -N shorthand + A..B range pari… Sonnet 5 patch 22 minutes ago