gabriel / muse public
test_cmd_commit_graph_enhancements.py python
223 lines 7.6 KB
Raw
sha256:51ce277f663e01a43eaffbe77509b1de7ac2d4251b55d23306304bcdeb92c90d feat(pack): delta-encode snapshots in MPackBundle wire format Sonnet 4.6 minor ⚠ breaking 121 days ago
1 """Tests for the new commit-graph flags: --count, --first-parent, --ancestry-path."""
2
3 from __future__ import annotations
4
5 import datetime
6 import json
7 import pathlib
8
9 import pytest
10 from tests.cli_test_helper import CliRunner
11
12 cli = None # argparse migration — CliRunner ignores this arg
13 from muse.core.snapshot import compute_commit_id, compute_snapshot_id
14 from muse.core.store import CommitRecord, SnapshotRecord, write_commit, write_snapshot
15 from muse.core.types import Manifest
16 from muse.core.paths import muse_dir, ref_path
17
18 runner = CliRunner()
19
20 _DT = datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc)
21
22
23
24 def _init_repo(path: pathlib.Path) -> pathlib.Path:
25 dot_muse = muse_dir(path)
26 (dot_muse / "commits").mkdir(parents=True)
27 (dot_muse / "snapshots").mkdir(parents=True)
28 (dot_muse / "objects").mkdir(parents=True)
29 (dot_muse / "refs" / "heads").mkdir(parents=True)
30 (dot_muse / "HEAD").write_text("ref: refs/heads/main", encoding="utf-8")
31 (dot_muse / "repo.json").write_text(
32 json.dumps({"repo_id": "test-repo", "domain": "midi"}), encoding="utf-8"
33 )
34 return path
35
36
37 def _env(repo: pathlib.Path) -> Manifest:
38 return {"MUSE_REPO_ROOT": str(repo)}
39
40
41 def _snap(repo: pathlib.Path, tag: str) -> str:
42 """Write an empty-manifest snapshot; return its content-addressed ID."""
43 sid = compute_snapshot_id({})
44 write_snapshot(
45 repo,
46 SnapshotRecord(
47 snapshot_id=sid,
48 manifest={},
49 created_at=_DT,
50 ),
51 )
52 return sid
53
54
55 def _commit(
56 repo: pathlib.Path,
57 tag: str,
58 branch: str = "main",
59 parent: str | None = None,
60 parent2: str | None = None,
61 ) -> str:
62 """Write a commit using *tag* as message (ensures uniqueness); return real commit ID."""
63 sid = _snap(repo, tag)
64 parent_ids = [p for p in [parent, parent2] if p is not None]
65 cid = compute_commit_id( parent_ids=parent_ids,
66 snapshot_id=sid,
67 message=tag,
68 committed_at_iso=_DT.isoformat(),
69 author="tester",
70 )
71 write_commit(
72 repo,
73 CommitRecord(
74 commit_id=cid,
75 repo_id="test-repo",
76 branch=branch,
77 snapshot_id=sid,
78 message=tag,
79 committed_at=_DT,
80 author="tester",
81 parent_commit_id=parent,
82 parent2_commit_id=parent2,
83 ),
84 )
85 branch_ref = ref_path(repo, branch)
86 branch_ref.parent.mkdir(parents=True, exist_ok=True)
87 branch_ref.write_text(cid, encoding="utf-8")
88 return cid
89
90
91 class TestCommitGraphCount:
92 def test_count_returns_integer(self, tmp_path: pathlib.Path) -> None:
93 _init_repo(tmp_path)
94 c1 = _commit(tmp_path, "a", parent=None)
95 _commit(tmp_path, "b", parent=c1)
96 result = runner.invoke(cli, ["commit-graph", "--count"], env=_env(tmp_path))
97 assert result.exit_code == 0
98 data = json.loads(result.output)
99 assert "count" in data
100 assert data["count"] == 2
101 assert "commits" not in data # full node list suppressed
102
103 def test_count_no_commits_returns_error(self, tmp_path: pathlib.Path) -> None:
104 _init_repo(tmp_path)
105 result = runner.invoke(cli, ["commit-graph", "--count"], env=_env(tmp_path))
106 assert result.exit_code != 0
107
108 def test_count_with_stop_at(self, tmp_path: pathlib.Path) -> None:
109 _init_repo(tmp_path)
110 base = _commit(tmp_path, "base", parent=None)
111 _commit(tmp_path, "feature", parent=base)
112 result = runner.invoke(
113 cli, ["commit-graph", "--stop-at", base, "--count"], env=_env(tmp_path)
114 )
115 assert result.exit_code == 0
116 data = json.loads(result.output)
117 assert data["count"] == 1 # only "feature", base excluded
118
119 def test_count_short_flag(self, tmp_path: pathlib.Path) -> None:
120 _init_repo(tmp_path)
121 _commit(tmp_path, "a")
122 result = runner.invoke(cli, ["commit-graph", "-c"], env=_env(tmp_path))
123 assert result.exit_code == 0
124 data = json.loads(result.output)
125 assert "count" in data
126
127
128 class TestCommitGraphFirstParent:
129 def test_first_parent_only(self, tmp_path: pathlib.Path) -> None:
130 _init_repo(tmp_path)
131 c1 = _commit(tmp_path, "c1", parent=None)
132 c2 = _commit(tmp_path, "c2", parent=c1)
133 result = runner.invoke(
134 cli, ["commit-graph", "--first-parent", "--count"], env=_env(tmp_path)
135 )
136 assert result.exit_code == 0
137 data = json.loads(result.output)
138 assert data["count"] == 2
139
140 def test_first_parent_excludes_merge_parent(self, tmp_path: pathlib.Path) -> None:
141 """With --first-parent, second parents of merges are not followed."""
142 _init_repo(tmp_path)
143 c1 = _commit(tmp_path, "c1", parent=None)
144 c2 = _commit(tmp_path, "branch_tip", "feat", parent=c1)
145 # merge commit with c1 as first parent, c2 as second parent
146 _commit(tmp_path, "merge", parent=c1, parent2=c2)
147 result = runner.invoke(
148 cli, ["commit-graph", "--first-parent", "--count"], env=_env(tmp_path)
149 )
150 assert result.exit_code == 0
151 data = json.loads(result.output)
152 # Should NOT follow c2 branch; only main chain: merge → c1
153 assert data["count"] == 2 # merge + c1
154
155 def test_first_parent_short_flag(self, tmp_path: pathlib.Path) -> None:
156 _init_repo(tmp_path)
157 _commit(tmp_path, "c1")
158 result = runner.invoke(
159 cli, ["commit-graph", "-1", "--count"], env=_env(tmp_path)
160 )
161 assert result.exit_code == 0
162
163
164 class TestCommitGraphAncestryPath:
165 def test_ancestry_path_requires_stop_at(self, tmp_path: pathlib.Path) -> None:
166 _init_repo(tmp_path)
167 _commit(tmp_path, "c1")
168 result = runner.invoke(
169 cli, ["commit-graph", "--ancestry-path"], env=_env(tmp_path)
170 )
171 assert result.exit_code != 0
172 data = json.loads(result.stderr)
173 assert "error" in data
174
175 def test_ancestry_path_with_stop_at_runs(self, tmp_path: pathlib.Path) -> None:
176 _init_repo(tmp_path)
177 base = _commit(tmp_path, "base", parent=None)
178 _commit(tmp_path, "feature", parent=base)
179 result = runner.invoke(
180 cli,
181 ["commit-graph", "--json", "--stop-at", base, "--ancestry-path"],
182 env=_env(tmp_path),
183 )
184 assert result.exit_code == 0
185 data = json.loads(result.output)
186 assert "commits" in data
187
188 def test_ancestry_path_short_flag(self, tmp_path: pathlib.Path) -> None:
189 _init_repo(tmp_path)
190 base = _commit(tmp_path, "base", parent=None)
191 _commit(tmp_path, "next", parent=base)
192 result = runner.invoke(
193 cli,
194 ["commit-graph", "--stop-at", base, "-a"],
195 env=_env(tmp_path),
196 )
197 assert result.exit_code == 0
198
199
200 class TestCommitGraphCombined:
201 def test_first_parent_and_count(self, tmp_path: pathlib.Path) -> None:
202 _init_repo(tmp_path)
203 c1 = _commit(tmp_path, "c1", parent=None)
204 _commit(tmp_path, "c2", parent=c1)
205 result = runner.invoke(
206 cli, ["commit-graph", "--first-parent", "--count"], env=_env(tmp_path)
207 )
208 assert result.exit_code == 0
209 data = json.loads(result.output)
210 assert data["count"] == 2
211
212 def test_count_always_emits_json(self, tmp_path: pathlib.Path) -> None:
213 """--count always emits JSON."""
214 _init_repo(tmp_path)
215 _commit(tmp_path, "c1")
216 result = runner.invoke(
217 cli,
218 ["commit-graph", "--count"],
219 env=_env(tmp_path),
220 )
221 assert result.exit_code == 0
222 data = json.loads(result.output)
223 assert "count" in data
File History 1 commit
sha256:51ce277f663e01a43eaffbe77509b1de7ac2d4251b55d23306304bcdeb92c90d feat(pack): delta-encode snapshots in MPackBundle wire format Sonnet 4.6 minor 121 days ago