test_footprint_integrity_purity.py python
72 lines 3.0 KB
Raw
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 1 day ago
1 """Data-integrity: `check_footprint_integrity` is a pure function of its inputs (§KH3.8)."""
2
3 from __future__ import annotations
4
5 from pathlib import Path
6
7 from cli.version_lock import ORIGIN_KIT, ORIGIN_PRESERVED, FootprintEntry, build_version_lock_from_entries
8 from tools.footprint_integrity import check_footprint_integrity
9
10
11 def _lock(entries: list[FootprintEntry]):
12 return build_version_lock_from_entries(
13 kit_version="0.1.0",
14 config_version=1,
15 entries=entries,
16 installed_at="2026-01-01T00:00:00Z",
17 )
18
19
20 def test_identical_state_yields_identical_report(tmp_path: Path) -> None:
21 (tmp_path / "present.mdc").write_text("x", encoding="utf-8")
22 lock = _lock(
23 [
24 FootprintEntry(path="present.mdc", source="s", sha256="0" * 64, origin=ORIGIN_KIT),
25 FootprintEntry(path="absent.mdc", source="s", sha256="0" * 64, origin=ORIGIN_KIT),
26 ]
27 )
28 first = check_footprint_integrity(tmp_path, lock=lock)
29 second = check_footprint_integrity(tmp_path, lock=lock)
30 assert first == second
31 assert first.missing == second.missing
32
33
34 def test_no_partial_state_on_repeated_calls(tmp_path: Path) -> None:
35 """No I/O side effects — running the check never mutates the repo or the lock."""
36 (tmp_path / "a.mdc").write_text("x", encoding="utf-8")
37 lock = _lock([FootprintEntry(path="a.mdc", source="s", sha256="0" * 64, origin=ORIGIN_KIT)])
38 before = (tmp_path / "a.mdc").read_text(encoding="utf-8")
39 for _ in range(10):
40 check_footprint_integrity(tmp_path, lock=lock)
41 after = (tmp_path / "a.mdc").read_text(encoding="utf-8")
42 assert before == after
43 assert lock.footprint == (
44 FootprintEntry(path="a.mdc", source="s", sha256="0" * 64, origin=ORIGIN_KIT),
45 ) or list(lock.footprint) == [
46 FootprintEntry(path="a.mdc", source="s", sha256="0" * 64, origin=ORIGIN_KIT)
47 ]
48
49
50 def test_varying_disk_state_yields_varying_report_deterministically(tmp_path: Path) -> None:
51 lock = _lock([FootprintEntry(path="a.mdc", source="s", sha256="0" * 64, origin=ORIGIN_KIT)])
52
53 absent_report = check_footprint_integrity(tmp_path, lock=lock)
54 assert absent_report.state == "missing"
55
56 (tmp_path / "a.mdc").write_text("x", encoding="utf-8")
57 present_report = check_footprint_integrity(tmp_path, lock=lock)
58 assert present_report.state == "ok"
59
60 (tmp_path / "a.mdc").unlink()
61 absent_again = check_footprint_integrity(tmp_path, lock=lock)
62 assert absent_again == absent_report
63
64
65 def test_origin_reclassification_changes_report_deterministically(tmp_path: Path) -> None:
66 """Marking an absent file `preserved` deterministically flips the outcome to ok."""
67 kit_lock = _lock([FootprintEntry(path="a.mdc", source="s", sha256="0" * 64, origin=ORIGIN_KIT)])
68 preserved_lock = _lock(
69 [FootprintEntry(path="a.mdc", source="s", sha256="0" * 64, origin=ORIGIN_PRESERVED)]
70 )
71 assert check_footprint_integrity(tmp_path, lock=kit_lock).state == "missing"
72 assert check_footprint_integrity(tmp_path, lock=preserved_lock).state == "ok"
File History 1 commit
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 1 day ago