-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtest_prepare_repository.py
More file actions
185 lines (143 loc) · 7.01 KB
/
Copy pathtest_prepare_repository.py
File metadata and controls
185 lines (143 loc) · 7.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
"""Tests for prepare_repository()."""
from __future__ import annotations
import importlib.metadata
import json
from pathlib import Path
from ai_prompt_auto_commit.common import PROMPTS_DIRECTORY
from ai_prompt_auto_commit.prepare_repository import get_default_claude_settings, get_default_assistant_guidelines, prepare_repository
# ---------------------------------------------------------------------------
# .prompts/ directory
# ---------------------------------------------------------------------------
def test_prompts_dir_created(repo: Path) -> None:
assert (repo / PROMPTS_DIRECTORY).is_dir()
# ---------------------------------------------------------------------------
# top-level .gitignore
# ---------------------------------------------------------------------------
def test_root_gitignore_contains_prompts_pattern(repo: Path) -> None:
gitignore = repo / ".gitignore"
assert gitignore.exists()
assert f"/{PROMPTS_DIRECTORY}/" in gitignore.read_text(encoding="utf-8").splitlines()
def test_root_gitignore_pattern_not_duplicated(repo: Path) -> None:
prepare_repository() # second run
gitignore = repo / ".gitignore"
lines = gitignore.read_text(encoding="utf-8").splitlines()
assert lines.count(f"/{PROMPTS_DIRECTORY}/") == 1
def test_root_gitignore_existing_content_preserved(repo: Path) -> None:
old_content = "*.pyc\n__pycache__\n"
(repo / ".gitignore").write_text(old_content, encoding="utf-8")
prepare_repository()
content = (repo / ".gitignore").read_text(encoding="utf-8")
assert content.startswith(old_content)
assert f"/{PROMPTS_DIRECTORY}/" in content
def test_root_gitignore_newline_added_when_missing(repo: Path) -> None:
(repo / ".gitignore").write_text("*.pyc", encoding="utf-8") # no trailing newline
prepare_repository()
lines = (repo / ".gitignore").read_text(encoding="utf-8").splitlines()
assert f"/{PROMPTS_DIRECTORY}/" in lines
assert lines[0] == "*.pyc"
# ---------------------------------------------------------------------------
# get_default_claude_settings
# ---------------------------------------------------------------------------
def test_get_default_claude_settings_returns_hook() -> None:
settings = get_default_claude_settings()
hooks = settings["hooks"]["UserPromptSubmit"][0]["hooks"]
assert any(h.get("id") == "ai-prompt-auto-commit" for h in hooks)
def test_get_default_claude_settings_version_matches_package() -> None:
settings = get_default_claude_settings()
hook = settings["hooks"]["UserPromptSubmit"][0]["hooks"][0]
expected = importlib.metadata.version("ai-prompt-auto-commit")
assert hook["version"] == expected
# ---------------------------------------------------------------------------
# get_default_assistant_guidelines
# ---------------------------------------------------------------------------
def test_get_default_assistant_guidelines_includes_header() -> None:
content = get_default_assistant_guidelines()
expected_header = f"""---
version: "{importlib.metadata.version("ai-prompt-auto-commit")}"
---
"""
assert content.startswith(expected_header)
def test_get_default_assistant_guidelines_only_one_header() -> None:
content = get_default_assistant_guidelines()
header_start = content.find("---")
assert header_start != -1
header_end = content.find("---", header_start + 3)
assert header_end != -1
# There should be no more --- before the content
next_header = content.find("---", header_end + 3)
assert next_header == -1, "Multiple headers found in assistant guidelines"
# ---------------------------------------------------------------------------
# .claude/settings.json
# ---------------------------------------------------------------------------
def _hook_ids(settings: dict) -> list[str]:
return [
h.get("id", "")
for matcher in settings.get("hooks", {}).get("UserPromptSubmit", [])
for h in matcher.get("hooks", [])
]
def test_claude_settings_created_from_scratch(repo: Path) -> None:
dest = repo / ".claude" / "settings.json"
assert dest.exists()
settings = json.loads(dest.read_text(encoding="utf-8"))
assert "ai-prompt-auto-commit" in _hook_ids(settings)
def test_claude_settings_hook_inserted_into_existing_file(repo: Path) -> None:
# Replace with a file that has other content but no hook, then re-run
dest = repo / ".claude" / "settings.json"
dest.write_text(json.dumps({"other": "value"}), encoding="utf-8")
prepare_repository()
settings = json.loads(dest.read_text(encoding="utf-8"))
assert settings["other"] == "value"
assert "ai-prompt-auto-commit" in _hook_ids(settings)
def test_claude_settings_hook_appended_to_existing_matcher(repo: Path) -> None:
# Replace with a file that has a different hook, then re-run
dest = repo / ".claude" / "settings.json"
dest.write_text(json.dumps({
"hooks": {
"UserPromptSubmit": [
{"hooks": [{"id": "other-hook", "type": "command", "command": "echo hi"}]}
]
}
}), encoding="utf-8")
prepare_repository()
ids = _hook_ids(json.loads(dest.read_text(encoding="utf-8")))
assert "other-hook" in ids
assert "ai-prompt-auto-commit" in ids
def test_claude_settings_hook_not_duplicated(repo: Path) -> None:
prepare_repository() # second run
dest = repo / ".claude" / "settings.json"
settings = json.loads(dest.read_text(encoding="utf-8"))
assert _hook_ids(settings).count("ai-prompt-auto-commit") == 1
def test_claude_settings_hook_has_version(repo: Path) -> None:
dest = repo / ".claude" / "settings.json"
settings = json.loads(dest.read_text(encoding="utf-8"))
hook = next(
h for matcher in settings["hooks"]["UserPromptSubmit"]
for h in matcher.get("hooks", [])
if h.get("id") == "ai-prompt-auto-commit"
)
expected = importlib.metadata.version("ai-prompt-auto-commit")
assert hook["version"] == expected
def test_claude_settings_hook_updated_on_rerun(repo: Path) -> None:
dest = repo / ".claude" / "settings.json"
# Corrupt the existing hook with stale content
settings = json.loads(dest.read_text(encoding="utf-8"))
for matcher in settings["hooks"]["UserPromptSubmit"]:
for h in matcher.get("hooks", []):
if h.get("id") == "ai-prompt-auto-commit":
h["version"] = "0.0.0"
h["command"] = "stale command"
h["extra_stale_key"] = "should be removed"
dest.write_text(json.dumps(settings, indent=2), encoding="utf-8")
prepare_repository()
settings = json.loads(dest.read_text(encoding="utf-8"))
hook = next(
h for matcher in settings["hooks"]["UserPromptSubmit"]
for h in matcher.get("hooks", [])
if h.get("id") == "ai-prompt-auto-commit"
)
expected = get_default_claude_settings()["hooks"]["UserPromptSubmit"][0]["hooks"][0]
assert hook == expected
assert "extra_stale_key" not in hook
def test_prepare_repository_returns_zero(repo: Path) -> None:
assert prepare_repository() == 0
assert repo.is_dir()