gabriel / muse public
test_plumbing_symbolic_ref.py python
161 lines 5.3 KB
96dd15b1 feat(plumbing): add symbolic-ref, for-each-ref, name-rev, check-ref-for… Gabriel Cardona <gabriel@tellurstori.com> 2d ago
1 """Tests for muse plumbing symbolic-ref."""
2
3 from __future__ import annotations
4
5 import datetime
6 import hashlib
7 import json
8 import pathlib
9
10 import pytest
11 from typer.testing import CliRunner
12
13 from muse.cli.app import cli
14 from muse.core.store import CommitRecord, SnapshotRecord, write_commit, write_snapshot
15
16 runner = CliRunner()
17
18
19 def _sha(tag: str) -> str:
20 return hashlib.sha256(tag.encode()).hexdigest()
21
22
23 def _init_repo(path: pathlib.Path, branch: str = "main") -> pathlib.Path:
24 muse = path / ".muse"
25 (muse / "commits").mkdir(parents=True)
26 (muse / "snapshots").mkdir(parents=True)
27 (muse / "objects").mkdir(parents=True)
28 (muse / "refs" / "heads").mkdir(parents=True)
29 (muse / "HEAD").write_text(f"ref: refs/heads/{branch}", encoding="utf-8")
30 (muse / "repo.json").write_text(
31 json.dumps({"repo_id": "test-repo", "domain": "midi"}), encoding="utf-8"
32 )
33 return path
34
35
36 def _env(repo: pathlib.Path) -> dict[str, str]:
37 return {"MUSE_REPO_ROOT": str(repo)}
38
39
40 def _snap(repo: pathlib.Path, tag: str = "snap") -> str:
41 sid = _sha(tag)
42 write_snapshot(
43 repo,
44 SnapshotRecord(
45 snapshot_id=sid,
46 manifest={},
47 created_at=datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc),
48 ),
49 )
50 return sid
51
52
53 def _commit(
54 repo: pathlib.Path,
55 tag: str,
56 snap_id: str,
57 branch: str = "main",
58 parent: str | None = None,
59 ) -> str:
60 cid = _sha(tag)
61 write_commit(
62 repo,
63 CommitRecord(
64 commit_id=cid,
65 repo_id="test-repo",
66 branch=branch,
67 snapshot_id=snap_id,
68 message=tag,
69 committed_at=datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc),
70 author="tester",
71 parent_commit_id=parent,
72 parent2_commit_id=None,
73 ),
74 )
75 ref_path = repo / ".muse" / "refs" / "heads" / branch
76 ref_path.parent.mkdir(parents=True, exist_ok=True)
77 ref_path.write_text(cid, encoding="utf-8")
78 return cid
79
80
81 class TestSymbolicRef:
82 def test_read_json_default(self, tmp_path: pathlib.Path) -> None:
83 _init_repo(tmp_path)
84 result = runner.invoke(cli, ["plumbing", "symbolic-ref", "HEAD"], env=_env(tmp_path))
85 assert result.exit_code == 0
86 data = json.loads(result.output)
87 assert data["ref"] == "HEAD"
88 assert data["branch"] == "main"
89 assert data["symbolic_target"] == "refs/heads/main"
90
91 def test_read_with_commit(self, tmp_path: pathlib.Path) -> None:
92 _init_repo(tmp_path)
93 sid = _snap(tmp_path)
94 cid = _commit(tmp_path, "c1", sid)
95 result = runner.invoke(cli, ["plumbing", "symbolic-ref", "HEAD"], env=_env(tmp_path))
96 assert result.exit_code == 0
97 data = json.loads(result.output)
98 assert data["commit_id"] == cid
99
100 def test_read_text_format(self, tmp_path: pathlib.Path) -> None:
101 _init_repo(tmp_path)
102 result = runner.invoke(
103 cli, ["plumbing", "symbolic-ref", "--format", "text", "HEAD"], env=_env(tmp_path)
104 )
105 assert result.exit_code == 0
106 assert result.output.strip() == "refs/heads/main"
107
108 def test_read_short_flag(self, tmp_path: pathlib.Path) -> None:
109 _init_repo(tmp_path)
110 result = runner.invoke(
111 cli,
112 ["plumbing", "symbolic-ref", "--format", "text", "--short", "HEAD"],
113 env=_env(tmp_path),
114 )
115 assert result.exit_code == 0
116 assert result.output.strip() == "main"
117
118 def test_set_switches_branch(self, tmp_path: pathlib.Path) -> None:
119 _init_repo(tmp_path)
120 sid = _snap(tmp_path)
121 _commit(tmp_path, "c1", sid, "main")
122 _commit(tmp_path, "c2", sid, "other")
123 result = runner.invoke(
124 cli, ["plumbing", "symbolic-ref", "--set", "other", "HEAD"], env=_env(tmp_path)
125 )
126 assert result.exit_code == 0
127 data = json.loads(result.output)
128 assert data["branch"] == "other"
129
130 def test_set_nonexistent_branch_errors(self, tmp_path: pathlib.Path) -> None:
131 _init_repo(tmp_path)
132 result = runner.invoke(
133 cli, ["plumbing", "symbolic-ref", "--set", "nonexistent", "HEAD"], env=_env(tmp_path)
134 )
135 assert result.exit_code != 0
136 data = json.loads(result.output)
137 assert "error" in data
138
139 def test_invalid_format_errors(self, tmp_path: pathlib.Path) -> None:
140 _init_repo(tmp_path)
141 result = runner.invoke(
142 cli, ["plumbing", "symbolic-ref", "--format", "xml", "HEAD"], env=_env(tmp_path)
143 )
144 assert result.exit_code != 0
145
146 def test_unsupported_ref_name_errors(self, tmp_path: pathlib.Path) -> None:
147 _init_repo(tmp_path)
148 result = runner.invoke(
149 cli, ["plumbing", "symbolic-ref", "MERGE_HEAD"], env=_env(tmp_path)
150 )
151 assert result.exit_code != 0
152 data = json.loads(result.output)
153 assert "error" in data
154
155 def test_no_commits_commit_id_none(self, tmp_path: pathlib.Path) -> None:
156 """Fresh repo with no commits: commit_id should be null."""
157 _init_repo(tmp_path)
158 result = runner.invoke(cli, ["plumbing", "symbolic-ref", "HEAD"], env=_env(tmp_path))
159 assert result.exit_code == 0
160 data = json.loads(result.output)
161 assert data["commit_id"] is None