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