gabriel / muse public
test_read_granular_stat.py python
186 lines 6.6 KB
Raw
sha256:a154bc65916614c833d5a40a10d81ba3eae0d0495b0afddd34dc34f18d5e91b8 fix: test suite alignment and typing audit — zero violations Sonnet 4.6 minor ⚠ breaking 22 days ago
1 """TDD — granular 3-tier stat in muse read output.
2
3 RD-1 Structured-delta path: directory insert counted as directory, not file
4 RD-2 Structured-delta path: symbol ops appear in Symbols line
5 RD-3 Fallback path: directory addition shows "A test/" with trailing slash
6 RD-4 Fallback path: summary says "Directories: 1 added" not "N file(s) changed"
7 RD-5 Fallback path: file + directory counted separately in summary
8 """
9 from __future__ import annotations
10
11 import datetime
12 import json
13 import pathlib
14 from collections.abc import Mapping
15
16 import pytest
17
18 from tests.cli_test_helper import CliRunner
19 from muse.core.paths import muse_dir, ref_path
20 from muse.core.object_store import write_object
21 from muse.core.ids import hash_commit, hash_snapshot
22 from muse.core.commits import CommitRecord, write_commit
23 from muse.core.snapshots import SnapshotRecord, write_snapshot
24 from muse.core.types import blob_id
25
26 runner = CliRunner()
27
28
29 # ---------------------------------------------------------------------------
30 # Helpers
31 # ---------------------------------------------------------------------------
32
33 def _init_repo(path: pathlib.Path) -> pathlib.Path:
34 dot = muse_dir(path)
35 for d in ("commits", "snapshots", "objects", "refs/heads", "code"):
36 (dot / d).mkdir(parents=True, exist_ok=True)
37 (dot / "HEAD").write_text("ref: refs/heads/main", encoding="utf-8")
38 (dot / "repo.json").write_text(
39 json.dumps({"repo_id": "read-stat-test", "domain": "code"}),
40 encoding="utf-8",
41 )
42 return path
43
44
45 def _make_commit(
46 root: pathlib.Path,
47 files: Mapping[str, bytes],
48 parent: str | None = None,
49 directories: list[str] | None = None,
50 ) -> str:
51 manifest: dict[str, str] = {}
52 for rel, content in files.items():
53 oid = blob_id(content)
54 write_object(root, oid, content)
55 manifest[rel] = oid
56 snap_id = hash_snapshot(manifest, directories or [])
57 write_snapshot(root, SnapshotRecord(
58 snapshot_id=snap_id, manifest=manifest, directories=directories or []
59 ))
60 committed_at = datetime.datetime.now(datetime.timezone.utc)
61 commit_id = hash_commit(
62 parent_ids=[parent] if parent else [],
63 snapshot_id=snap_id,
64 message="test commit",
65 committed_at_iso=committed_at.isoformat(),
66 )
67 write_commit(root, CommitRecord(
68 commit_id=commit_id, branch="main", snapshot_id=snap_id,
69 message="test commit", committed_at=committed_at,
70 parent_commit_id=parent,
71 ))
72 ref_path(root, "main").write_text(commit_id, encoding="utf-8")
73 return commit_id
74
75
76 def _env(root: pathlib.Path) -> Mapping[str, str]:
77 return {"MUSE_REPO_ROOT": str(root)}
78
79
80 def _read(root: pathlib.Path) -> str:
81 return runner.invoke(None, ["read"], env=_env(root)).output
82
83
84 # ---------------------------------------------------------------------------
85 # RD-3 Fallback path: directory shown as "A test/" with trailing slash
86 # ---------------------------------------------------------------------------
87
88 class TestFallbackPathDirectoryDisplay:
89 def test_directory_shows_with_trailing_slash(
90 self, tmp_path: pathlib.Path
91 ) -> None:
92 root = _init_repo(tmp_path)
93 c1 = _make_commit(root, {"readme.md": b"# hi\n"})
94 _make_commit(root, {"readme.md": b"# hi\n"}, parent=c1, directories=["test"])
95
96 out = _read(root)
97
98 assert "A test/" in out, f"Expected 'A test/' in:\n{out}"
99
100 def test_directory_not_shown_without_slash(
101 self, tmp_path: pathlib.Path
102 ) -> None:
103 root = _init_repo(tmp_path)
104 c1 = _make_commit(root, {"readme.md": b"# hi\n"})
105 _make_commit(root, {"readme.md": b"# hi\n"}, parent=c1, directories=["test"])
106
107 out = _read(root)
108
109 assert "A test\n" not in out, f"'A test' (no slash) must not appear in:\n{out}"
110
111
112 # ---------------------------------------------------------------------------
113 # RD-4 Fallback path: summary shows granular directory/file breakdown
114 # ---------------------------------------------------------------------------
115
116 class TestFallbackPathSummary:
117 def test_directory_only_shows_directory_summary(
118 self, tmp_path: pathlib.Path
119 ) -> None:
120 """Adding only an empty dir: summary must say 'directory', not 'file(s)'."""
121 root = _init_repo(tmp_path)
122 c1 = _make_commit(root, {"readme.md": b"# hi\n"})
123 _make_commit(root, {"readme.md": b"# hi\n"}, parent=c1, directories=["test"])
124
125 out = _read(root)
126
127 assert "director" in out.lower(), f"Expected 'directory' in summary:\n{out}"
128 assert "file(s) changed" not in out, (
129 f"'file(s) changed' must not appear for directory-only commit:\n{out}"
130 )
131
132 def test_file_only_shows_file_summary(
133 self, tmp_path: pathlib.Path
134 ) -> None:
135 root = _init_repo(tmp_path)
136 c1 = _make_commit(root, {"readme.md": b"# hi\n"})
137 _make_commit(root, {"readme.md": b"# hi\n", "new.py": b"x=1\n"}, parent=c1)
138
139 out = _read(root)
140
141 assert "file" in out.lower()
142 assert "file(s) changed" not in out
143
144 def test_file_and_directory_counted_separately(
145 self, tmp_path: pathlib.Path
146 ) -> None:
147 root = _init_repo(tmp_path)
148 c1 = _make_commit(root, {"readme.md": b"# hi\n"})
149 _make_commit(
150 root,
151 {"readme.md": b"# hi\n", "new.py": b"x=1\n"},
152 parent=c1,
153 directories=["mydir"],
154 )
155
156 out = _read(root)
157
158 assert "director" in out.lower()
159 assert "file" in out.lower()
160
161
162 # ---------------------------------------------------------------------------
163 # RD-1 Structured-delta path: directory op not counted as file
164 # ---------------------------------------------------------------------------
165
166 class TestStructuredDeltaPath:
167 def test_directory_insert_not_counted_as_file(
168 self, tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
169 ) -> None:
170 """After a real muse commit that adds a dir, read --stat must say directory."""
171 root = _init_repo(tmp_path)
172 _make_commit(root, {"readme.md": b"# hi\n"})
173 monkeypatch.chdir(root)
174 (root / "mydir").mkdir()
175 runner.invoke(None, ["code", "add", "mydir/"], env=_env(root))
176 runner.invoke(None, ["commit", "-m", "add mydir"], env=_env(root))
177
178 out = _read(root)
179
180 assert "director" in out.lower(), f"Expected 'directory' in:\n{out}"
181 # Files line must not count the directory
182 if "Files:" in out:
183 files_line = [l for l in out.splitlines() if "Files:" in l][0]
184 assert "mydir" not in files_line, (
185 f"Directory must not appear in Files line: {files_line}"
186 )
File History 2 commits
sha256:a154bc65916614c833d5a40a10d81ba3eae0d0495b0afddd34dc34f18d5e91b8 fix: test suite alignment and typing audit — zero violations Sonnet 4.6 minor 22 days ago
sha256:3767afb72520f9b56053bb98fd83d323f738ee4cad16e306e8cf6862608380e4 feat: first-class directory tracking across status, diff, r… Sonnet 4.6 minor 22 days ago