gabriel / muse public
test_log_collect_all_commits.py python
137 lines 4.6 KB
Raw
sha256:f6cd81bc71702f5c1c6890bd39aaba994fe58c75f019d7c03934724fa2739bb4 fix: carry dev changes harmony dropped in merge — detached … Sonnet 4.6 minor ⚠ breaking 15 days ago
1 """TDD — log._collect_all_commits must use iter_ancestors, not inline deque BFS.
2
3 LC1 Structural — _collect_all_commits uses iter_ancestors; no inline deque BFS
4 LC2 Behavioural — collects all commits reachable from start_ids
5 LC3 Behavioural — truncated flag fires at max_commits cap
6 """
7 from __future__ import annotations
8
9 import datetime
10 import inspect
11 import json
12 import pathlib
13
14 import pytest
15
16 from muse._version import __version__
17 from muse.core.object_store import write_object
18 from muse.core.ids import hash_commit as compute_commit_id, hash_snapshot as compute_snapshot_id
19 from muse.core.commits import (
20 CommitRecord,
21 write_commit,
22 )
23 from muse.core.snapshots import (
24 SnapshotRecord,
25 write_snapshot,
26 )
27 from muse.core.types import blob_id
28 from muse.core.paths import muse_dir
29
30
31 def _repo(tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> pathlib.Path:
32 dot_muse = muse_dir(tmp_path)
33 for d in ("commits", "snapshots", "objects", "refs/heads", "remotes"):
34 (dot_muse / d).mkdir(parents=True, exist_ok=True)
35 (dot_muse / "HEAD").write_text("ref: refs/heads/main\n")
36 (dot_muse / "repo.json").write_text(
37 json.dumps({"repo_id": "test-repo", "schema_version": __version__, "domain": "code"})
38 )
39 monkeypatch.setenv("MUSE_REPO_ROOT", str(tmp_path))
40 monkeypatch.chdir(tmp_path)
41 return tmp_path
42
43
44 def _make_commit(
45 root: pathlib.Path,
46 parent_id: str | None = None,
47 *,
48 message: str = "test",
49 ) -> CommitRecord:
50 oid = blob_id(b"data-" + message.encode())
51 write_object(root, oid, b"data-" + message.encode())
52 manifest = {"f.py": oid}
53 snap_id = compute_snapshot_id(manifest)
54 write_snapshot(root, SnapshotRecord(snapshot_id=snap_id, manifest=manifest))
55 ts = datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc)
56 cid = compute_commit_id(
57 parent_ids=[parent_id] if parent_id else [],
58 snapshot_id=snap_id,
59 message=message,
60 committed_at_iso=ts.isoformat(),
61 )
62 rec = CommitRecord(
63 commit_id=cid,
64 branch="main",
65 snapshot_id=snap_id,
66 message=message,
67 committed_at=ts,
68 parent_commit_id=parent_id,
69 )
70 write_commit(root, rec)
71 return rec
72
73
74 # ---------------------------------------------------------------------------
75 # LC1 Structural
76 # ---------------------------------------------------------------------------
77
78 def test_lc1_collect_all_commits_uses_iter_ancestors() -> None:
79 """_collect_all_commits must delegate to iter_ancestors; no inline deque."""
80 from muse.cli.commands import log as log_mod
81
82 src = inspect.getsource(log_mod._collect_all_commits)
83
84 assert "iter_ancestors" in src, (
85 "_collect_all_commits must delegate to iter_ancestors. "
86 "Replace the inline deque BFS."
87 )
88 assert "deque" not in src, (
89 "_collect_all_commits still has an inline deque. Replace with iter_ancestors."
90 )
91
92
93 # ---------------------------------------------------------------------------
94 # LC2 Behavioural — collects all reachable commits
95 # ---------------------------------------------------------------------------
96
97 def test_lc2_collect_all_commits_returns_all(
98 tmp_path: pathlib.Path,
99 monkeypatch: pytest.MonkeyPatch,
100 ) -> None:
101 """Returns a CommitIndex containing every reachable commit."""
102 from muse.cli.commands.log import _collect_all_commits # type: ignore[attr-defined]
103
104 root = _repo(tmp_path, monkeypatch)
105 c1 = _make_commit(root, message="c1")
106 c2 = _make_commit(root, c1.commit_id, message="c2")
107 c3 = _make_commit(root, c2.commit_id, message="c3")
108
109 index, truncated = _collect_all_commits(root, [c3.commit_id])
110
111 assert truncated is False
112 assert c1.commit_id in index
113 assert c2.commit_id in index
114 assert c3.commit_id in index
115
116
117 # ---------------------------------------------------------------------------
118 # LC3 Behavioural — truncated flag
119 # ---------------------------------------------------------------------------
120
121 def test_lc3_collect_all_commits_truncated_flag(
122 tmp_path: pathlib.Path,
123 monkeypatch: pytest.MonkeyPatch,
124 ) -> None:
125 """truncated=True when max_commits is reached before exhausting the DAG."""
126 from muse.cli.commands.log import _collect_all_commits # type: ignore[attr-defined]
127
128 root = _repo(tmp_path, monkeypatch)
129 parent_id: str | None = None
130 for i in range(5):
131 c = _make_commit(root, parent_id, message=f"c{i}")
132 parent_id = c.commit_id
133
134 index, truncated = _collect_all_commits(root, [parent_id], max_commits=2) # type: ignore[arg-type]
135
136 assert truncated is True
137 assert len(index) == 2
File History 2 commits
sha256:fb67fed5a4d3e40de84bdd163de94ef1386570bef1dd1a020a732c8a038962ce Merge branch 'dev' into main Human 20 days ago