84 lines
2.9 KiB
Python
84 lines
2.9 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from beaver.plugins.hashing import hash_plugin_skill_tree
|
|
|
|
|
|
def test_skill_tree_hash_changes_when_supporting_file_changes(tmp_path: Path) -> None:
|
|
root = tmp_path / "skill"
|
|
root.mkdir()
|
|
(root / "SKILL.md").write_text("# Skill\n", encoding="utf-8")
|
|
(root / "templates").mkdir()
|
|
template = root / "templates" / "report.md"
|
|
template.write_text("v1", encoding="utf-8")
|
|
|
|
first = hash_plugin_skill_tree(root)
|
|
template.write_text("v2", encoding="utf-8")
|
|
second = hash_plugin_skill_tree(root)
|
|
|
|
assert first.skill_content_hash == second.skill_content_hash
|
|
assert first.skill_tree_hash != second.skill_tree_hash
|
|
|
|
|
|
def test_skill_tree_hash_changes_when_path_changes(tmp_path: Path) -> None:
|
|
root = tmp_path / "skill"
|
|
root.mkdir()
|
|
(root / "SKILL.md").write_text("# Skill\n", encoding="utf-8")
|
|
(root / "a.txt").write_text("same", encoding="utf-8")
|
|
first = hash_plugin_skill_tree(root)
|
|
|
|
(root / "b.txt").write_text((root / "a.txt").read_text(encoding="utf-8"), encoding="utf-8")
|
|
(root / "a.txt").unlink()
|
|
second = hash_plugin_skill_tree(root)
|
|
|
|
assert first.skill_tree_hash != second.skill_tree_hash
|
|
|
|
|
|
def test_skill_tree_hash_tracks_executable_bit_but_not_other_mode_bits(tmp_path: Path) -> None:
|
|
root = tmp_path / "skill"
|
|
root.mkdir()
|
|
script = root / "script.sh"
|
|
(root / "SKILL.md").write_text("# Skill\n", encoding="utf-8")
|
|
script.write_text("#!/bin/sh\n", encoding="utf-8")
|
|
script.chmod(0o644)
|
|
first = hash_plugin_skill_tree(root)
|
|
|
|
script.chmod(0o600)
|
|
non_exec_changed = hash_plugin_skill_tree(root)
|
|
script.chmod(0o700)
|
|
exec_changed = hash_plugin_skill_tree(root)
|
|
|
|
assert first.skill_tree_hash == non_exec_changed.skill_tree_hash
|
|
assert first.skill_tree_hash != exec_changed.skill_tree_hash
|
|
|
|
|
|
def test_skill_tree_hash_ignores_mtime_and_beaver_metadata(tmp_path: Path) -> None:
|
|
root = tmp_path / "skill"
|
|
root.mkdir()
|
|
skill = root / "SKILL.md"
|
|
skill.write_text("# Skill\n", encoding="utf-8")
|
|
(root / "version.json").write_text('{"ignored": true}', encoding="utf-8")
|
|
(root / "upstream.json").write_text('{"ignored": true}', encoding="utf-8")
|
|
first = hash_plugin_skill_tree(root)
|
|
|
|
os.utime(skill, (skill.stat().st_atime + 20, skill.stat().st_mtime + 20))
|
|
(root / "version.json").write_text('{"ignored": false}', encoding="utf-8")
|
|
(root / "upstream.json").write_text('{"ignored": false}', encoding="utf-8")
|
|
second = hash_plugin_skill_tree(root)
|
|
|
|
assert first.skill_tree_hash == second.skill_tree_hash
|
|
|
|
|
|
def test_skill_tree_hash_rejects_symlinks(tmp_path: Path) -> None:
|
|
root = tmp_path / "skill"
|
|
root.mkdir()
|
|
(root / "SKILL.md").write_text("# Skill\n", encoding="utf-8")
|
|
(root / "linked").symlink_to(root / "SKILL.md")
|
|
|
|
with pytest.raises(ValueError, match="symlink"):
|
|
hash_plugin_skill_tree(root)
|