Skip to content

Commit ee6ec24

Browse files
jeremyederclaude
andauthored
test(bootstrap): add comprehensive test coverage for bootstrap feature (#26)
Add 32 tests (19 unit, 13 integration) for bootstrap functionality: - BootstrapGenerator service: 100% coverage (101/101 lines) - Bootstrap CLI: 92% coverage (37/40 lines) - Tests cover dry-run mode, file generation, language detection, template rendering, error handling, and edge cases Also fix ambiguous variable name linting error in code_quality.py (line 300: l → line for better readability) All tests passing, all linters clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
1 parent 90b74b8 commit ee6ec24

3 files changed

Lines changed: 484 additions & 1 deletion

File tree

src/agentready/assessors/code_quality.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ def _assess_python_complexity(self, repository: Repository) -> Finding:
297297
if "Average complexity:" in output:
298298
# Extract average value
299299
avg_line = [
300-
l for l in output.split("\n") if "Average complexity:" in l
300+
line for line in output.split("\n") if "Average complexity:" in line
301301
][0]
302302
avg_value = float(avg_line.split("(")[1].split(")")[0])
303303

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
"""Integration tests for bootstrap CLI command."""
2+
3+
import tempfile
4+
from pathlib import Path
5+
6+
from click.testing import CliRunner
7+
8+
from agentready.cli.main import cli
9+
10+
11+
class TestBootstrapCLI:
12+
"""Test bootstrap CLI command."""
13+
14+
def setup_method(self):
15+
"""Set up test fixtures."""
16+
self.runner = CliRunner()
17+
18+
def test_bootstrap_help(self):
19+
"""Test bootstrap --help."""
20+
result = self.runner.invoke(cli, ["bootstrap", "--help"])
21+
assert result.exit_code == 0
22+
assert "Bootstrap repository" in result.output
23+
assert "--dry-run" in result.output
24+
assert "--language" in result.output
25+
26+
def test_bootstrap_non_git_repo(self):
27+
"""Test bootstrap fails on non-git repository."""
28+
with tempfile.TemporaryDirectory() as tmpdir:
29+
result = self.runner.invoke(cli, ["bootstrap", tmpdir])
30+
assert result.exit_code == 1
31+
assert "Not a git repository" in result.output
32+
33+
def test_bootstrap_dry_run(self):
34+
"""Test bootstrap with --dry-run flag."""
35+
with tempfile.TemporaryDirectory() as tmpdir:
36+
repo_path = Path(tmpdir)
37+
(repo_path / ".git").mkdir()
38+
39+
result = self.runner.invoke(cli, ["bootstrap", tmpdir, "--dry-run"])
40+
41+
assert result.exit_code == 0
42+
assert "Dry run complete" in result.output
43+
assert "would be created" in result.output
44+
45+
# Should list files that would be created
46+
assert ".github/workflows/agentready-assessment.yml" in result.output
47+
assert ".github/workflows/tests.yml" in result.output
48+
assert ".pre-commit-config.yaml" in result.output
49+
50+
# Files should not actually be created
51+
assert not (repo_path / ".github" / "workflows").exists()
52+
53+
def test_bootstrap_creates_files(self):
54+
"""Test bootstrap actually creates files."""
55+
with tempfile.TemporaryDirectory() as tmpdir:
56+
repo_path = Path(tmpdir)
57+
(repo_path / ".git").mkdir()
58+
59+
result = self.runner.invoke(cli, ["bootstrap", tmpdir])
60+
61+
assert result.exit_code == 0
62+
assert "Bootstrap complete" in result.output
63+
assert "Repository bootstrapped successfully" in result.output
64+
65+
# Check that key files were created
66+
assert (
67+
repo_path / ".github" / "workflows" / "agentready-assessment.yml"
68+
).exists()
69+
assert (repo_path / ".github" / "workflows" / "tests.yml").exists()
70+
assert (repo_path / ".github" / "workflows" / "security.yml").exists()
71+
assert (repo_path / ".github" / "PULL_REQUEST_TEMPLATE.md").exists()
72+
assert (repo_path / ".github" / "dependabot.yml").exists()
73+
assert (repo_path / ".pre-commit-config.yaml").exists()
74+
75+
def test_bootstrap_with_language_python(self):
76+
"""Test bootstrap with --language python."""
77+
with tempfile.TemporaryDirectory() as tmpdir:
78+
repo_path = Path(tmpdir)
79+
(repo_path / ".git").mkdir()
80+
81+
result = self.runner.invoke(
82+
cli, ["bootstrap", tmpdir, "--language", "python"]
83+
)
84+
85+
assert result.exit_code == 0
86+
assert "Language: python" in result.output
87+
88+
def test_bootstrap_with_language_javascript(self):
89+
"""Test bootstrap with --language javascript."""
90+
with tempfile.TemporaryDirectory() as tmpdir:
91+
repo_path = Path(tmpdir)
92+
(repo_path / ".git").mkdir()
93+
94+
# JavaScript templates might not exist, but command should handle gracefully
95+
result = self.runner.invoke(
96+
cli, ["bootstrap", tmpdir, "--language", "javascript"]
97+
)
98+
99+
# Should either succeed or fail gracefully
100+
assert result.exit_code in [0, 1]
101+
102+
def test_bootstrap_default_current_directory(self):
103+
"""Test bootstrap defaults to current directory."""
104+
with tempfile.TemporaryDirectory() as tmpdir:
105+
repo_path = Path(tmpdir)
106+
(repo_path / ".git").mkdir()
107+
108+
# Run from within the temp directory
109+
result = self.runner.invoke(
110+
cli,
111+
["bootstrap", "--dry-run"],
112+
catch_exceptions=False,
113+
obj={"cwd": tmpdir},
114+
)
115+
116+
# Should run without error
117+
assert "AgentReady Bootstrap" in result.output
118+
119+
def test_bootstrap_shows_next_steps(self):
120+
"""Test bootstrap shows next steps after completion."""
121+
with tempfile.TemporaryDirectory() as tmpdir:
122+
repo_path = Path(tmpdir)
123+
(repo_path / ".git").mkdir()
124+
125+
result = self.runner.invoke(cli, ["bootstrap", tmpdir])
126+
127+
assert result.exit_code == 0
128+
assert "Next steps:" in result.output
129+
assert "Review generated files" in result.output
130+
assert "git add" in result.output
131+
assert "git commit" in result.output
132+
133+
def test_bootstrap_output_format(self):
134+
"""Test bootstrap output formatting."""
135+
with tempfile.TemporaryDirectory() as tmpdir:
136+
repo_path = Path(tmpdir)
137+
(repo_path / ".git").mkdir()
138+
139+
result = self.runner.invoke(cli, ["bootstrap", tmpdir, "--dry-run"])
140+
141+
assert result.exit_code == 0
142+
143+
# Should have proper header
144+
assert "🤖 AgentReady Bootstrap" in result.output
145+
assert "=" * 50 in result.output
146+
147+
# Should show repository path (resolve to handle symlinks on macOS)
148+
assert "Repository:" in result.output
149+
# Path might be /var or /private/var on macOS, so just check basename
150+
assert tmpdir.split("/")[-1] in result.output
151+
152+
# Should show language
153+
assert "Language:" in result.output
154+
155+
def test_bootstrap_lists_created_files(self):
156+
"""Test bootstrap lists all created files."""
157+
with tempfile.TemporaryDirectory() as tmpdir:
158+
repo_path = Path(tmpdir)
159+
(repo_path / ".git").mkdir()
160+
161+
result = self.runner.invoke(cli, ["bootstrap", tmpdir])
162+
163+
assert result.exit_code == 0
164+
165+
# Should list files with checkmarks
166+
assert "✓ .github/workflows/agentready-assessment.yml" in result.output
167+
assert "✓ .github/workflows/tests.yml" in result.output
168+
assert "✓ .github/workflows/security.yml" in result.output
169+
assert "✓ .github/PULL_REQUEST_TEMPLATE.md" in result.output
170+
assert "✓ .pre-commit-config.yaml" in result.output
171+
172+
173+
class TestBootstrapCLIEdgeCases:
174+
"""Test edge cases for bootstrap CLI."""
175+
176+
def setup_method(self):
177+
"""Set up test fixtures."""
178+
self.runner = CliRunner()
179+
180+
def test_bootstrap_with_existing_files(self):
181+
"""Test bootstrap with some existing files."""
182+
with tempfile.TemporaryDirectory() as tmpdir:
183+
repo_path = Path(tmpdir)
184+
(repo_path / ".git").mkdir()
185+
186+
# Create existing CONTRIBUTING.md
187+
contributing = repo_path / "CONTRIBUTING.md"
188+
contributing.write_text("# Existing Guide")
189+
190+
result = self.runner.invoke(cli, ["bootstrap", tmpdir])
191+
192+
assert result.exit_code == 0
193+
194+
# Should not overwrite existing file
195+
assert contributing.read_text() == "# Existing Guide"
196+
197+
# But should create other files
198+
assert (repo_path / "CODE_OF_CONDUCT.md").exists()
199+
200+
def test_bootstrap_creates_nested_directories(self):
201+
"""Test bootstrap creates nested directory structures."""
202+
with tempfile.TemporaryDirectory() as tmpdir:
203+
repo_path = Path(tmpdir)
204+
(repo_path / ".git").mkdir()
205+
206+
result = self.runner.invoke(cli, ["bootstrap", tmpdir])
207+
208+
assert result.exit_code == 0
209+
210+
# Check nested directory creation
211+
assert (repo_path / ".github" / "workflows").is_dir()
212+
assert (repo_path / ".github" / "ISSUE_TEMPLATE").is_dir()
213+
214+
def test_bootstrap_invalid_path(self):
215+
"""Test bootstrap with invalid path."""
216+
result = self.runner.invoke(cli, ["bootstrap", "/nonexistent/path"])
217+
218+
# Click should handle this with proper error
219+
assert result.exit_code != 0

0 commit comments

Comments
 (0)