gabriel / muse public
test_cmd_describe.py python
256 lines 8.6 KB
Raw
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 131 days ago
1 """Tests for ``muse describe`` and ``muse/core/describe.py``.
2
3 Covers: no tags fallback to SHA, tag at tip, tag behind tip (distance),
4 --long format, --require-tag exit-1, --format json, core describe_commit,
5 stress: deep ancestry.
6 """
7
8 from __future__ import annotations
9
10 import datetime
11 import json
12 import pathlib
13
14 import pytest
15 from tests.cli_test_helper import CliRunner
16
17 cli = None # argparse migration — CliRunner ignores this arg
18 from muse.core.describe import describe_commit
19 from muse.core.object_store import write_object
20 from muse.core.snapshot import compute_commit_id, compute_snapshot_id
21 from muse.core.store import CommitRecord, SnapshotRecord, TagRecord, write_commit, write_snapshot, write_tag
22 from muse.core._types import Manifest, blob_id
23
24 runner = CliRunner()
25
26 from muse.core._types import content_hash as _content_hash
27 _REPO_ID = _content_hash({"name": "describe-test"})
28
29
30 # ---------------------------------------------------------------------------
31 # Helpers
32 # ---------------------------------------------------------------------------
33
34
35 def _sha(data: bytes) -> str:
36 return blob_id(data)
37
38
39 def _init_repo(path: pathlib.Path) -> pathlib.Path:
40 muse = path / ".muse"
41 for d in ("commits", "snapshots", "objects", "refs/heads", "tags"):
42 (muse / d).mkdir(parents=True, exist_ok=True)
43 (muse / "HEAD").write_text("ref: refs/heads/main", encoding="utf-8")
44 (muse / "repo.json").write_text(
45 json.dumps({"repo_id": _REPO_ID, "domain": "midi"}), encoding="utf-8"
46 )
47 return path
48
49
50 def _env(repo: pathlib.Path) -> Manifest:
51 return {"MUSE_REPO_ROOT": str(repo)}
52
53
54 def _make_commit(
55 root: pathlib.Path,
56 parent_id: str | None = None,
57 content: bytes = b"data",
58 branch: str = "main",
59 ) -> str:
60 obj_id = _sha(content)
61 write_object(root, obj_id, content)
62 manifest = {f"file_{obj_id[7:15]}.txt": obj_id}
63 snap_id = compute_snapshot_id(manifest)
64 write_snapshot(root, SnapshotRecord(snapshot_id=snap_id, manifest=manifest))
65 committed_at = datetime.datetime.now(datetime.timezone.utc)
66 parent_ids = [parent_id] if parent_id else []
67 commit_id = compute_commit_id(
68 repo_id=_REPO_ID,
69 parent_ids=parent_ids,
70 snapshot_id=snap_id,
71 message=f"commit on {branch}",
72 committed_at_iso=committed_at.isoformat(),
73 )
74 write_commit(root, CommitRecord(
75 commit_id=commit_id,
76 repo_id=_REPO_ID,
77 created_on_branch=branch,
78 snapshot_id=snap_id,
79 message=f"commit on {branch}",
80 committed_at=committed_at,
81 parent_commit_id=parent_id,
82 ))
83 (root / ".muse" / "refs" / "heads" / branch).write_text(commit_id, encoding="utf-8")
84 return commit_id
85
86
87 def _make_tag(root: pathlib.Path, tag: str, commit_id: str) -> None:
88 write_tag(root, TagRecord(
89 tag_id=_content_hash({"tag": tag, "commit_id": commit_id}),
90 tag=tag,
91 commit_id=commit_id,
92 repo_id=_REPO_ID,
93 created_at=datetime.datetime.now(datetime.timezone.utc),
94 ))
95
96
97 # ---------------------------------------------------------------------------
98 # Unit: core describe_commit
99 # ---------------------------------------------------------------------------
100
101
102 def test_describe_no_tags_returns_short_sha(tmp_path: pathlib.Path) -> None:
103 _init_repo(tmp_path)
104 cid = _make_commit(tmp_path, content=b"alpha")
105 result = describe_commit(tmp_path, _REPO_ID, cid)
106 assert result["tag"] is None
107 assert result["short_sha"] == cid[:len("sha256:") + 12]
108 assert result["name"] == result["short_sha"]
109
110
111 def test_describe_tag_at_tip(tmp_path: pathlib.Path) -> None:
112 _init_repo(tmp_path)
113 cid = _make_commit(tmp_path, content=b"beta")
114 _make_tag(tmp_path, "v1.0.0", cid)
115 result = describe_commit(tmp_path, _REPO_ID, cid)
116 assert result["tag"] == "v1.0.0"
117 assert result["distance"] == 0
118 assert result["name"] == "v1.0.0"
119
120
121 def test_describe_tag_one_hop_behind(tmp_path: pathlib.Path) -> None:
122 _init_repo(tmp_path)
123 cid1 = _make_commit(tmp_path, content=b"first")
124 _make_tag(tmp_path, "v0.9.0", cid1)
125 cid2 = _make_commit(tmp_path, parent_id=cid1, content=b"second")
126 result = describe_commit(tmp_path, _REPO_ID, cid2)
127 assert result["tag"] == "v0.9.0"
128 assert result["distance"] == 1
129 assert result["name"] == "v0.9.0~1"
130
131
132 def test_describe_long_format(tmp_path: pathlib.Path) -> None:
133 _init_repo(tmp_path)
134 cid = _make_commit(tmp_path, content=b"gamma")
135 _make_tag(tmp_path, "v2.0.0", cid)
136 result = describe_commit(tmp_path, _REPO_ID, cid, long_format=True)
137 assert result["tag"] == "v2.0.0"
138 assert result["distance"] == 0
139 # Long format always includes distance + short_sha (no git-style 'g' prefix).
140 assert result["name"].startswith("v2.0.0-0-sha256:")
141
142
143 # ---------------------------------------------------------------------------
144 # CLI: muse describe
145 # ---------------------------------------------------------------------------
146
147
148 def test_describe_cli_help() -> None:
149 result = runner.invoke(cli, ["describe", "--help"])
150 assert result.exit_code == 0
151 assert "--long" in result.output or "-l" in result.output
152
153
154 def test_describe_cli_no_commits(tmp_path: pathlib.Path) -> None:
155 _init_repo(tmp_path)
156 result = runner.invoke(cli, ["describe"], env=_env(tmp_path))
157 assert result.exit_code != 0
158
159
160 def test_describe_cli_text_output(tmp_path: pathlib.Path) -> None:
161 _init_repo(tmp_path)
162 cid = _make_commit(tmp_path, content=b"cli-test")
163 _make_tag(tmp_path, "v3.0.0", cid)
164 result = runner.invoke(cli, ["describe"], env=_env(tmp_path))
165 assert result.exit_code == 0
166 assert "v3.0.0" in result.output
167
168
169 def test_describe_cli_json_output(tmp_path: pathlib.Path) -> None:
170 _init_repo(tmp_path)
171 cid = _make_commit(tmp_path, content=b"json-test")
172 _make_tag(tmp_path, "v4.0.0", cid)
173 result = runner.invoke(cli, ["describe", "--json"], env=_env(tmp_path))
174 assert result.exit_code == 0
175 data = json.loads(result.output)
176 assert data["tag"] == "v4.0.0"
177 assert data["distance"] == 0
178 assert "commit_id" in data
179
180
181 def test_describe_cli_require_tag_fails_without_tags(tmp_path: pathlib.Path) -> None:
182 _init_repo(tmp_path)
183 _make_commit(tmp_path, content=b"no-tags")
184 result = runner.invoke(cli, ["describe", "--require-tag"], env=_env(tmp_path))
185 assert result.exit_code != 0
186
187
188 def test_describe_cli_long_flag(tmp_path: pathlib.Path) -> None:
189 _init_repo(tmp_path)
190 cid = _make_commit(tmp_path, content=b"long")
191 _make_tag(tmp_path, "v5.0.0", cid)
192 result = runner.invoke(cli, ["describe", "--long"], env=_env(tmp_path))
193 assert result.exit_code == 0
194 assert "v5.0.0-0-sha256:" in result.output
195
196
197 def test_describe_cli_short_flags(tmp_path: pathlib.Path) -> None:
198 _init_repo(tmp_path)
199 cid = _make_commit(tmp_path, content=b"short-flags")
200 _make_tag(tmp_path, "v6.0.0", cid)
201 result = runner.invoke(cli, ["describe", "-l", "--json"], env=_env(tmp_path))
202 assert result.exit_code == 0
203 data = json.loads(result.output)
204 assert "v6.0.0" in data["name"]
205
206
207 # ---------------------------------------------------------------------------
208 # Stress: deep ancestry (100 commits, tag at root)
209 # ---------------------------------------------------------------------------
210
211
212 def test_describe_stress_deep_ancestry(tmp_path: pathlib.Path) -> None:
213 _init_repo(tmp_path)
214 prev: str | None = None
215 first_commit_id = ""
216 for i in range(100):
217 cid = _make_commit(tmp_path, parent_id=prev, content=f"step {i}".encode())
218 if i == 0:
219 first_commit_id = cid
220 prev = cid
221
222 _make_tag(tmp_path, "v-root", first_commit_id)
223 assert prev is not None
224 result = describe_commit(tmp_path, _REPO_ID, prev)
225 assert result["tag"] == "v-root"
226 assert result["distance"] == 99
227 assert "v-root~99" == result["name"]
228
229
230 class TestRegisterFlags:
231 def test_default_json_out_is_false(self):
232 import argparse
233 from muse.cli.commands.describe import register
234 p = argparse.ArgumentParser()
235 subs = p.add_subparsers()
236 register(subs)
237 args = p.parse_args(["describe"])
238 assert args.json_out is False
239
240 def test_json_flag_sets_json_out(self):
241 import argparse
242 from muse.cli.commands.describe import register
243 p = argparse.ArgumentParser()
244 subs = p.add_subparsers()
245 register(subs)
246 args = p.parse_args(["describe", "--json"])
247 assert args.json_out is True
248
249 def test_j_shorthand_sets_json_out(self):
250 import argparse
251 from muse.cli.commands.describe import register
252 p = argparse.ArgumentParser()
253 subs = p.add_subparsers()
254 register(subs)
255 args = p.parse_args(["describe", "-j"])
256 assert args.json_out is True
File History 3 commits
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 131 days ago
sha256:7f9e2ef5286aedad9c1e6011b4c46ca27f39dbdad6e3409357e36b26e46b3b7c docs: docstring sprint for-each-ref→hotspots — idiomatic ru… Sonnet 4.6 patch 137 days ago
sha256:a09b1b4f6838754495547f200aa0ce88e2f56ffc5b20b900f6f0cff2c3cdede9 fix(cursorignore): remove git-ism (.git/worktrees) Human minor 140 days ago