cgcardona / muse public
test_core_snapshot.py python
139 lines 5.1 KB
e6786943 feat: upgrade to Python 3.14, drop from __future__ import annotations Gabriel Cardona <cgcardona@gmail.com> 1d ago
1 """Tests for muse.core.snapshot — content-addressed snapshot computation."""
2
3 import pathlib
4
5 import pytest
6
7 from muse.core.snapshot import (
8 build_snapshot_manifest,
9 compute_commit_id,
10 compute_snapshot_id,
11 diff_workdir_vs_snapshot,
12 hash_file,
13 )
14
15
16 @pytest.fixture
17 def workdir(tmp_path: pathlib.Path) -> pathlib.Path:
18 d = tmp_path / "muse-work"
19 d.mkdir()
20 return d
21
22
23 class TestHashFile:
24 def test_consistent(self, tmp_path: pathlib.Path) -> None:
25 f = tmp_path / "file.mid"
26 f.write_bytes(b"hello world")
27 assert hash_file(f) == hash_file(f)
28
29 def test_different_content_different_hash(self, tmp_path: pathlib.Path) -> None:
30 a = tmp_path / "a.mid"
31 b = tmp_path / "b.mid"
32 a.write_bytes(b"aaa")
33 b.write_bytes(b"bbb")
34 assert hash_file(a) != hash_file(b)
35
36 def test_known_hash(self, tmp_path: pathlib.Path) -> None:
37 import hashlib
38 content = b"muse"
39 f = tmp_path / "f.mid"
40 f.write_bytes(content)
41 expected = hashlib.sha256(content).hexdigest()
42 assert hash_file(f) == expected
43
44
45 class TestBuildSnapshotManifest:
46 def test_empty_workdir(self, workdir: pathlib.Path) -> None:
47 assert build_snapshot_manifest(workdir) == {}
48
49 def test_single_file(self, workdir: pathlib.Path) -> None:
50 (workdir / "beat.mid").write_bytes(b"drums")
51 manifest = build_snapshot_manifest(workdir)
52 assert "beat.mid" in manifest
53 assert len(manifest["beat.mid"]) == 64 # sha256 hex
54
55 def test_nested_file(self, workdir: pathlib.Path) -> None:
56 (workdir / "tracks").mkdir()
57 (workdir / "tracks" / "bass.mid").write_bytes(b"bass")
58 manifest = build_snapshot_manifest(workdir)
59 assert "tracks/bass.mid" in manifest
60
61 def test_hidden_files_excluded(self, workdir: pathlib.Path) -> None:
62 (workdir / ".DS_Store").write_bytes(b"junk")
63 (workdir / "beat.mid").write_bytes(b"drums")
64 manifest = build_snapshot_manifest(workdir)
65 assert ".DS_Store" not in manifest
66 assert "beat.mid" in manifest
67
68 def test_deterministic_order(self, workdir: pathlib.Path) -> None:
69 for name in ["c.mid", "a.mid", "b.mid"]:
70 (workdir / name).write_bytes(name.encode())
71 m1 = build_snapshot_manifest(workdir)
72 m2 = build_snapshot_manifest(workdir)
73 assert m1 == m2
74
75
76 class TestComputeSnapshotId:
77 def test_empty_manifest(self) -> None:
78 sid = compute_snapshot_id({})
79 assert len(sid) == 64
80
81 def test_deterministic(self) -> None:
82 manifest = {"a.mid": "hash1", "b.mid": "hash2"}
83 assert compute_snapshot_id(manifest) == compute_snapshot_id(manifest)
84
85 def test_order_independent(self) -> None:
86 m1 = {"a.mid": "h1", "b.mid": "h2"}
87 m2 = {"b.mid": "h2", "a.mid": "h1"}
88 assert compute_snapshot_id(m1) == compute_snapshot_id(m2)
89
90 def test_different_content_different_id(self) -> None:
91 m1 = {"a.mid": "h1"}
92 m2 = {"a.mid": "h2"}
93 assert compute_snapshot_id(m1) != compute_snapshot_id(m2)
94
95
96 class TestComputeCommitId:
97 def test_deterministic(self) -> None:
98 kwargs = dict(parent_ids=["p1"], snapshot_id="s1", message="msg", committed_at_iso="2026-01-01T00:00:00+00:00")
99 assert compute_commit_id(**kwargs) == compute_commit_id(**kwargs)
100
101 def test_parent_order_independent(self) -> None:
102 a = compute_commit_id(parent_ids=["p1", "p2"], snapshot_id="s1", message="m", committed_at_iso="t")
103 b = compute_commit_id(parent_ids=["p2", "p1"], snapshot_id="s1", message="m", committed_at_iso="t")
104 assert a == b
105
106 def test_different_messages_different_ids(self) -> None:
107 a = compute_commit_id(parent_ids=[], snapshot_id="s1", message="msg1", committed_at_iso="t")
108 b = compute_commit_id(parent_ids=[], snapshot_id="s1", message="msg2", committed_at_iso="t")
109 assert a != b
110
111
112 class TestDiffWorkdirVsSnapshot:
113 def test_new_repo_all_untracked(self, workdir: pathlib.Path) -> None:
114 (workdir / "beat.mid").write_bytes(b"x")
115 added, modified, deleted, untracked = diff_workdir_vs_snapshot(workdir, {})
116 assert added == set()
117 assert untracked == {"beat.mid"}
118
119 def test_added_file(self, workdir: pathlib.Path) -> None:
120 (workdir / "beat.mid").write_bytes(b"x")
121 last = {"other.mid": "abc"}
122 added, modified, deleted, untracked = diff_workdir_vs_snapshot(workdir, last)
123 assert "beat.mid" in added
124 assert "other.mid" in deleted
125
126 def test_modified_file(self, workdir: pathlib.Path) -> None:
127 f = workdir / "beat.mid"
128 f.write_bytes(b"new content")
129 last = {"beat.mid": "oldhash"}
130 added, modified, deleted, untracked = diff_workdir_vs_snapshot(workdir, last)
131 assert "beat.mid" in modified
132
133 def test_clean_workdir(self, workdir: pathlib.Path) -> None:
134 f = workdir / "beat.mid"
135 f.write_bytes(b"content")
136 from muse.core.snapshot import hash_file
137 h = hash_file(f)
138 added, modified, deleted, untracked = diff_workdir_vs_snapshot(workdir, {"beat.mid": h})
139 assert not added and not modified and not deleted and not untracked