gabriel / muse public
test_commit_dir_changes.py python
184 lines 6.5 KB
Raw
sha256:81ae324db5ad375fbfe4834c6fcb378312cafad3cc92dec5d3e5c427306621a2 fix: remove commit_exists filter from have anchors — server… Sonnet 4.6 patch 21 days ago
1 """Directory changes in ``muse commit`` and ``muse read`` output.
2
3 When a commit adds or removes empty directories, those changes must be
4 visible in both the commit summary line and in ``muse read --json``,
5 alongside the existing ``files_added`` / ``files_removed`` fields.
6
7 Coverage matrix
8 ---------------
9 DC Directory changes in commit / read output
10 DC1 commit adding an empty dir → dirs_added: ["foobar/"] in muse read
11 DC2 commit removing a committed dir → dirs_removed: ["emptydir/"] in muse read
12 DC3 total_changes in muse read includes dir changes
13 DC4 commit summary line mentions directory additions ("1 dir added")
14 DC5 commit summary line mentions directory removals ("1 dir removed")
15 DC6 commit with only file changes → dirs_added: [] and dirs_removed: []
16 DC7 dirs_added and dirs_removed always present in muse read --json
17 """
18
19 from __future__ import annotations
20
21 import json
22 import pathlib
23 from collections.abc import Mapping
24
25 import pytest
26
27 from tests.cli_test_helper import CliRunner
28
29 cli = None
30 runner = CliRunner()
31
32
33 # ---------------------------------------------------------------------------
34 # Helpers
35 # ---------------------------------------------------------------------------
36
37
38 def _env(root: pathlib.Path) -> Mapping[str, str]:
39 return {"MUSE_REPO_ROOT": str(root)}
40
41
42 def _run(root: pathlib.Path, *args: str) -> str:
43 result = runner.invoke(cli, list(args), env=_env(root))
44 assert result.exit_code == 0, f"{args} failed:\n{result.output}\n{result.stderr}"
45 return result.output.strip()
46
47
48 def _read(root: pathlib.Path) -> Mapping[str, object]:
49 return json.loads(_run(root, "read", "--json"))
50
51
52 # ---------------------------------------------------------------------------
53 # Fixtures
54 # ---------------------------------------------------------------------------
55
56
57 @pytest.fixture()
58 def base_repo(tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> pathlib.Path:
59 """Code repo with one committed file, clean working tree."""
60 monkeypatch.chdir(tmp_path)
61 _run(tmp_path, "init", "--domain", "code")
62 (tmp_path / "main.py").write_text("x = 1\n")
63 _run(tmp_path, "code", "add", ".")
64 _run(tmp_path, "commit", "-m", "initial")
65 return tmp_path
66
67
68 @pytest.fixture()
69 def repo_with_committed_dir(
70 tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
71 ) -> pathlib.Path:
72 """Code repo with a committed empty directory ``emptydir``."""
73 monkeypatch.chdir(tmp_path)
74 _run(tmp_path, "init", "--domain", "code")
75 (tmp_path / "main.py").write_text("x = 1\n")
76 (tmp_path / "emptydir").mkdir()
77 _run(tmp_path, "code", "add", ".")
78 _run(tmp_path, "commit", "-m", "initial with emptydir")
79 return tmp_path
80
81
82 # ---------------------------------------------------------------------------
83 # DC Directory changes in commit / read
84 # ---------------------------------------------------------------------------
85
86
87 class TestCommitDirChanges:
88 def test_DC1_dirs_added_in_read_json(self, base_repo: pathlib.Path) -> None:
89 """DC1: commit adding an empty dir → dirs_added: ['foobar/'] in muse read."""
90 root = base_repo
91 (root / "foobar").mkdir()
92 _run(root, "code", "add", "foobar")
93 _run(root, "commit", "-m", "add foobar dir")
94
95 data = _read(root)
96
97 assert "dirs_added" in data, "muse read --json must have a 'dirs_added' key"
98 assert "foobar/" in data["dirs_added"], (
99 "newly committed empty dir must appear in dirs_added with trailing slash"
100 )
101
102 def test_DC2_dirs_removed_in_read_json(
103 self, repo_with_committed_dir: pathlib.Path
104 ) -> None:
105 """DC2: commit removing a committed dir → dirs_removed: ['emptydir/']."""
106 root = repo_with_committed_dir
107 (root / "emptydir").rmdir()
108 _run(root, "code", "add", ".")
109 _run(root, "commit", "-m", "remove emptydir")
110
111 data = _read(root)
112
113 assert "dirs_removed" in data, "muse read --json must have a 'dirs_removed' key"
114 assert "emptydir/" in data["dirs_removed"], (
115 "removed committed dir must appear in dirs_removed with trailing slash"
116 )
117
118 def test_DC3_total_changes_includes_dirs(self, base_repo: pathlib.Path) -> None:
119 """DC3: total_changes in muse read includes directory additions."""
120 root = base_repo
121 (root / "foobar").mkdir()
122 _run(root, "code", "add", "foobar")
123 _run(root, "commit", "-m", "add foobar dir")
124
125 data = _read(root)
126
127 assert data["total_changes"] == 1, (
128 "adding one empty dir must count as 1 total change"
129 )
130
131 def test_DC4_commit_summary_mentions_dir_added(
132 self, base_repo: pathlib.Path
133 ) -> None:
134 """DC4: commit summary line mentions directory additions."""
135 root = base_repo
136 (root / "foobar").mkdir()
137 _run(root, "code", "add", "foobar")
138
139 result = runner.invoke(
140 cli, ["commit", "-m", "add foobar dir"], env=_env(root)
141 )
142 assert result.exit_code == 0
143 assert "dir" in result.output.lower(), (
144 f"commit output must mention directory change; got:\n{result.output}"
145 )
146
147 def test_DC5_commit_summary_mentions_dir_removed(
148 self, repo_with_committed_dir: pathlib.Path
149 ) -> None:
150 """DC5: commit summary line mentions directory removals."""
151 root = repo_with_committed_dir
152 (root / "emptydir").rmdir()
153 _run(root, "code", "add", ".")
154
155 result = runner.invoke(
156 cli, ["commit", "-m", "remove emptydir"], env=_env(root)
157 )
158 assert result.exit_code == 0
159 assert "dir" in result.output.lower(), (
160 f"commit output must mention directory removal; got:\n{result.output}"
161 )
162
163 def test_DC6_no_dir_changes_gives_empty_lists(
164 self, base_repo: pathlib.Path
165 ) -> None:
166 """DC6: commit with only file changes → dirs_added: [] and dirs_removed: []."""
167 root = base_repo
168 (root / "other.py").write_text("y = 2\n")
169 _run(root, "code", "add", ".")
170 _run(root, "commit", "-m", "add other.py")
171
172 data = _read(root)
173
174 assert data["dirs_added"] == []
175 assert data["dirs_removed"] == []
176
177 def test_DC7_dirs_keys_always_present(self, base_repo: pathlib.Path) -> None:
178 """DC7: dirs_added and dirs_removed always present in muse read --json."""
179 data = _read(base_repo)
180
181 assert "dirs_added" in data
182 assert "dirs_removed" in data
183 assert isinstance(data["dirs_added"], list)
184 assert isinstance(data["dirs_removed"], list)
File History 3 commits
sha256:81ae324db5ad375fbfe4834c6fcb378312cafad3cc92dec5d3e5c427306621a2 fix: remove commit_exists filter from have anchors — server… Sonnet 4.6 patch 21 days ago
sha256:36c3cb3e76619d4c30a6d9bf81b5ec4ff148e30dcfed913e3114ca7b43b81c7e fix: rename objects→blobs in push client and all stale test… Sonnet 4.6 patch 22 days ago
sha256:09656d1b0772ea4c96f8911d7bf8042b33eb0596992c6546dfab3d21e9dee330 fix: align muse read --json schema and test contracts Sonnet 4.6 minor 23 days ago