gabriel / muse public
test_plumbing_rev_parse.py python
221 lines 8.3 KB
99746394 feat(tests+docs): supercharge plumbing test suite and update reference doc Gabriel Cardona <gabriel@tellurstori.com> 2d ago
1 """Tests for ``muse plumbing rev-parse``.
2
3 Covers: HEAD resolution, branch-name resolution, full commit-ID passthrough,
4 abbreviated-prefix resolution, ambiguous-prefix detection, not-found errors,
5 text-format output, bad-format handling, and an empty-branch edge case.
6 """
7
8 from __future__ import annotations
9
10 import datetime
11 import hashlib
12 import json
13 import pathlib
14
15 from typer.testing import CliRunner
16
17 from muse.cli.app import cli
18 from muse.core.errors import ExitCode
19 from muse.core.store import CommitRecord, SnapshotRecord, write_commit, write_snapshot
20
21 runner = CliRunner()
22
23
24 # ---------------------------------------------------------------------------
25 # Helpers
26 # ---------------------------------------------------------------------------
27
28
29 def _sha(tag: str) -> str:
30 return hashlib.sha256(tag.encode()).hexdigest()
31
32
33 def _init_repo(path: pathlib.Path) -> pathlib.Path:
34 muse = path / ".muse"
35 (muse / "commits").mkdir(parents=True)
36 (muse / "snapshots").mkdir(parents=True)
37 (muse / "objects").mkdir(parents=True)
38 (muse / "refs" / "heads").mkdir(parents=True)
39 (muse / "HEAD").write_text("ref: refs/heads/main", encoding="utf-8")
40 (muse / "repo.json").write_text(
41 json.dumps({"repo_id": "test-repo", "domain": "midi"}), encoding="utf-8"
42 )
43 return path
44
45
46 def _env(repo: pathlib.Path) -> dict[str, str]:
47 return {"MUSE_REPO_ROOT": str(repo)}
48
49
50 def _snap(repo: pathlib.Path, tag: str = "snap") -> str:
51 sid = _sha(f"snap-{tag}")
52 write_snapshot(
53 repo,
54 SnapshotRecord(
55 snapshot_id=sid,
56 manifest={},
57 created_at=datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc),
58 ),
59 )
60 return sid
61
62
63 def _commit(
64 repo: pathlib.Path, tag: str, sid: str, branch: str = "main", parent: str | None = None
65 ) -> str:
66 cid = _sha(tag)
67 write_commit(
68 repo,
69 CommitRecord(
70 commit_id=cid,
71 repo_id="test-repo",
72 branch=branch,
73 snapshot_id=sid,
74 message=tag,
75 committed_at=datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc),
76 author="tester",
77 parent_commit_id=parent,
78 ),
79 )
80 ref = repo / ".muse" / "refs" / "heads" / branch
81 ref.parent.mkdir(parents=True, exist_ok=True)
82 ref.write_text(cid, encoding="utf-8")
83 return cid
84
85
86 # ---------------------------------------------------------------------------
87 # Unit: HEAD resolution
88 # ---------------------------------------------------------------------------
89
90
91 class TestRevParseHead:
92 def test_head_resolves_to_current_branch_commit(self, tmp_path: pathlib.Path) -> None:
93 repo = _init_repo(tmp_path)
94 sid = _snap(repo)
95 cid = _commit(repo, "first", sid)
96 result = runner.invoke(cli, ["plumbing", "rev-parse", "HEAD"], env=_env(repo))
97 assert result.exit_code == 0, result.output
98 data = json.loads(result.stdout)
99 assert data["commit_id"] == cid
100 assert data["ref"] == "HEAD"
101
102 def test_head_case_insensitive(self, tmp_path: pathlib.Path) -> None:
103 repo = _init_repo(tmp_path)
104 sid = _snap(repo)
105 cid = _commit(repo, "c1", sid)
106 for variant in ("head", "Head", "hEaD"):
107 result = runner.invoke(cli, ["plumbing", "rev-parse", variant], env=_env(repo))
108 assert result.exit_code == 0
109 assert json.loads(result.stdout)["commit_id"] == cid
110
111 def test_head_on_empty_branch_exits_user_error(self, tmp_path: pathlib.Path) -> None:
112 repo = _init_repo(tmp_path) # No commits yet.
113 result = runner.invoke(cli, ["plumbing", "rev-parse", "HEAD"], env=_env(repo))
114 assert result.exit_code == ExitCode.USER_ERROR
115 assert "error" in json.loads(result.stdout)
116
117
118 # ---------------------------------------------------------------------------
119 # Integration: branch-name resolution
120 # ---------------------------------------------------------------------------
121
122
123 class TestRevParseBranch:
124 def test_branch_name_resolves_to_tip_commit(self, tmp_path: pathlib.Path) -> None:
125 repo = _init_repo(tmp_path)
126 sid = _snap(repo)
127 cid = _commit(repo, "tip", sid, branch="feature")
128 (repo / ".muse" / "HEAD").write_text("ref: refs/heads/main", encoding="utf-8")
129 result = runner.invoke(cli, ["plumbing", "rev-parse", "feature"], env=_env(repo))
130 assert result.exit_code == 0
131 assert json.loads(result.stdout)["commit_id"] == cid
132
133 def test_nonexistent_branch_not_found(self, tmp_path: pathlib.Path) -> None:
134 repo = _init_repo(tmp_path)
135 result = runner.invoke(cli, ["plumbing", "rev-parse", "no-such-branch"], env=_env(repo))
136 assert result.exit_code == ExitCode.USER_ERROR
137 assert json.loads(result.stdout)["error"] == "not found"
138
139 def test_multiple_branches_each_resolve_independently(self, tmp_path: pathlib.Path) -> None:
140 repo = _init_repo(tmp_path)
141 sid = _snap(repo)
142 cid_main = _commit(repo, "main-c", sid, branch="main")
143 cid_dev = _commit(repo, "dev-c", sid, branch="dev")
144 r_main = runner.invoke(cli, ["plumbing", "rev-parse", "main"], env=_env(repo))
145 r_dev = runner.invoke(cli, ["plumbing", "rev-parse", "dev"], env=_env(repo))
146 assert json.loads(r_main.stdout)["commit_id"] == cid_main
147 assert json.loads(r_dev.stdout)["commit_id"] == cid_dev
148
149
150 # ---------------------------------------------------------------------------
151 # Integration: full & abbreviated commit ID
152 # ---------------------------------------------------------------------------
153
154
155 class TestRevParseCommitId:
156 def test_full_64_char_id_resolves(self, tmp_path: pathlib.Path) -> None:
157 repo = _init_repo(tmp_path)
158 sid = _snap(repo)
159 cid = _commit(repo, "commit", sid)
160 result = runner.invoke(cli, ["plumbing", "rev-parse", cid], env=_env(repo))
161 assert result.exit_code == 0
162 assert json.loads(result.stdout)["commit_id"] == cid
163
164 def test_prefix_resolves_when_unique(self, tmp_path: pathlib.Path) -> None:
165 repo = _init_repo(tmp_path)
166 sid = _snap(repo)
167 cid = _commit(repo, "unique-prefix", sid)
168 prefix = cid[:12]
169 result = runner.invoke(cli, ["plumbing", "rev-parse", prefix], env=_env(repo))
170 assert result.exit_code == 0
171 assert json.loads(result.stdout)["commit_id"] == cid
172
173 def test_unknown_full_id_exits_not_found(self, tmp_path: pathlib.Path) -> None:
174 repo = _init_repo(tmp_path)
175 ghost = _sha("ghost-commit")
176 result = runner.invoke(cli, ["plumbing", "rev-parse", ghost], env=_env(repo))
177 assert result.exit_code == ExitCode.USER_ERROR
178
179
180 # ---------------------------------------------------------------------------
181 # Integration: format flags
182 # ---------------------------------------------------------------------------
183
184
185 class TestRevParseFormats:
186 def test_text_format_emits_bare_commit_id(self, tmp_path: pathlib.Path) -> None:
187 repo = _init_repo(tmp_path)
188 sid = _snap(repo)
189 cid = _commit(repo, "text", sid)
190 result = runner.invoke(
191 cli, ["plumbing", "rev-parse", "--format", "text", "main"], env=_env(repo)
192 )
193 assert result.exit_code == 0
194 assert result.stdout.strip() == cid
195
196 def test_short_format_flag(self, tmp_path: pathlib.Path) -> None:
197 repo = _init_repo(tmp_path)
198 sid = _snap(repo)
199 cid = _commit(repo, "short", sid)
200 result = runner.invoke(cli, ["plumbing", "rev-parse", "-f", "text", "main"], env=_env(repo))
201 assert result.exit_code == 0
202 assert result.stdout.strip() == cid
203
204 def test_bad_format_exits_user_error(self, tmp_path: pathlib.Path) -> None:
205 repo = _init_repo(tmp_path)
206 sid = _snap(repo)
207 _commit(repo, "x", sid)
208 result = runner.invoke(
209 cli, ["plumbing", "rev-parse", "--format", "toml", "main"], env=_env(repo)
210 )
211 assert result.exit_code == ExitCode.USER_ERROR
212
213 def test_json_output_has_ref_and_commit_id_keys(self, tmp_path: pathlib.Path) -> None:
214 repo = _init_repo(tmp_path)
215 sid = _snap(repo)
216 _commit(repo, "kv", sid)
217 result = runner.invoke(cli, ["plumbing", "rev-parse", "main"], env=_env(repo))
218 assert result.exit_code == 0
219 data = json.loads(result.stdout)
220 assert "ref" in data
221 assert "commit_id" in data