ed9bade863
project-files/: - CLAUDE.md.template (266 lines) - docs/Pravila_raboty_Claude.template.md (720 lines) - docs/Plugin_stack_rules.template.md (916 lines) - docs/Tooling.template.md (613 lines) - docs/CHANGELOG_claude_md.template.md - docs/visualizations/hooks-skills-plugins-map.html (3122 lines) - .mcp.json.template (universal: playwright/github/semgrep; laravel-boost dropped) user-level-files/: - hooks/ (10 Python files: skill-marker, skill-check, economy-* x8) - settings-fragment.json (enabledPlugins + permissions + hooks only) - marketplaces.json (3 sources) - plugins-manifest.json (4 plugins pinned with gitCommitSha) - mcp-user.template.json (magic with <<MAGIC_API_KEY>> placeholder) Gitleaks scan: 0 findings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
117 lines
4.1 KiB
Python
117 lines
4.1 KiB
Python
"""Tests for economy-self-check.py hook.
|
|
Tests via subprocess + temporary HOME mocking."""
|
|
import json
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
|
|
SCRIPT = os.path.expanduser("~/.claude/hooks/economy-self-check.py")
|
|
|
|
|
|
def run_with_temp_home(setup):
|
|
"""Run self-check with a temporary HOME directory that has `setup` files.
|
|
`setup` is a dict {relative_path: contents_or_None_for_dir}."""
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
for rel, content in setup.items():
|
|
full = os.path.join(tmp, rel)
|
|
os.makedirs(os.path.dirname(full), exist_ok=True)
|
|
if content is not None:
|
|
with open(full, "w", encoding="utf-8") as f:
|
|
f.write(content)
|
|
env = os.environ.copy()
|
|
env["HOME"] = tmp
|
|
env["USERPROFILE"] = tmp
|
|
env["PYTHONIOENCODING"] = "utf-8"
|
|
r = subprocess.run(
|
|
["python", SCRIPT],
|
|
input=b"{}",
|
|
capture_output=True,
|
|
timeout=10,
|
|
env=env,
|
|
)
|
|
return r.stdout.decode("utf-8", errors="replace"), r.returncode
|
|
|
|
|
|
# Minimal valid settings.json content
|
|
VALID_SETTINGS = json.dumps({
|
|
"hooks": {
|
|
"UserPromptSubmit": [{
|
|
"hooks": [{"type": "command", "command": "python ~/.claude/hooks/economy-mode.py"}]
|
|
}]
|
|
}
|
|
})
|
|
|
|
DUMMY_PY = "# placeholder\n"
|
|
|
|
|
|
def test_all_present_silent():
|
|
"""All hooks + settings + python — should be silent."""
|
|
out, rc = run_with_temp_home({
|
|
".claude/hooks/skill-marker.py": DUMMY_PY,
|
|
".claude/hooks/skill-check.py": DUMMY_PY,
|
|
".claude/hooks/economy-mode.py": DUMMY_PY,
|
|
".claude/hooks/economy-self-check.py": DUMMY_PY,
|
|
".claude/hooks/economy-state-guard.py": DUMMY_PY,
|
|
".claude/hooks/economy-verifier.py": DUMMY_PY,
|
|
".claude/hooks/economy-postcompact.py": DUMMY_PY,
|
|
".claude/settings.json": VALID_SETTINGS,
|
|
})
|
|
assert out.strip() == "", f"Expected silent, got: {out!r}"
|
|
print(" PASS: all_present_silent")
|
|
|
|
|
|
def test_economy_mode_missing_warns():
|
|
out, rc = run_with_temp_home({
|
|
".claude/hooks/skill-marker.py": DUMMY_PY,
|
|
".claude/hooks/skill-check.py": DUMMY_PY,
|
|
# economy-mode.py missing
|
|
".claude/hooks/economy-self-check.py": DUMMY_PY,
|
|
".claude/hooks/economy-state-guard.py": DUMMY_PY,
|
|
".claude/hooks/economy-verifier.py": DUMMY_PY,
|
|
".claude/hooks/economy-postcompact.py": DUMMY_PY,
|
|
".claude/settings.json": VALID_SETTINGS,
|
|
})
|
|
assert "economy-mode.py" in out, f"Expected economy-mode warning, got: {out!r}"
|
|
print(" PASS: economy_mode_missing_warns")
|
|
|
|
|
|
def test_settings_invalid_json_warns():
|
|
out, rc = run_with_temp_home({
|
|
".claude/hooks/skill-marker.py": DUMMY_PY,
|
|
".claude/hooks/skill-check.py": DUMMY_PY,
|
|
".claude/hooks/economy-mode.py": DUMMY_PY,
|
|
".claude/hooks/economy-self-check.py": DUMMY_PY,
|
|
".claude/hooks/economy-state-guard.py": DUMMY_PY,
|
|
".claude/hooks/economy-verifier.py": DUMMY_PY,
|
|
".claude/hooks/economy-postcompact.py": DUMMY_PY,
|
|
".claude/settings.json": "{ invalid json",
|
|
})
|
|
assert "settings.json" in out, f"Expected settings warning, got: {out!r}"
|
|
print(" PASS: settings_invalid_json_warns")
|
|
|
|
|
|
def test_hook_not_registered_warns():
|
|
out, rc = run_with_temp_home({
|
|
".claude/hooks/skill-marker.py": DUMMY_PY,
|
|
".claude/hooks/skill-check.py": DUMMY_PY,
|
|
".claude/hooks/economy-mode.py": DUMMY_PY,
|
|
".claude/hooks/economy-self-check.py": DUMMY_PY,
|
|
".claude/hooks/economy-state-guard.py": DUMMY_PY,
|
|
".claude/hooks/economy-verifier.py": DUMMY_PY,
|
|
".claude/hooks/economy-postcompact.py": DUMMY_PY,
|
|
".claude/settings.json": json.dumps({"hooks": {}}), # no UserPromptSubmit
|
|
})
|
|
assert "registered" in out or "UserPromptSubmit" in out, \
|
|
f"Expected registration warning, got: {out!r}"
|
|
print(" PASS: hook_not_registered_warns")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_all_present_silent()
|
|
test_economy_mode_missing_warns()
|
|
test_settings_invalid_json_warns()
|
|
test_hook_not_registered_warns()
|
|
print("\n=== 4/4 PASSED ===")
|