Skip to content

Commit a1a548f

Browse files
test: add CLI-level tests for remove --category, stats nonexistent dir, and --ignore option (#30)
Sentinel-approved: 2 files, 36 additions. CLI guard for nonexistent dirs + 4 focused tests.
1 parent 48877fb commit a1a548f

2 files changed

Lines changed: 36 additions & 0 deletions

File tree

src/deadcode/cli.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ def remove(ctx: click.Context, dry_run: bool, category: str | None) -> None:
171171
project = ctx.obj["project"]
172172
ignore = _merge_config_ignore(ctx)
173173

174+
if not Path(project).exists():
175+
err_console.print(f"[red]Project directory '{project}' not found.[/red]")
176+
sys.exit(1)
177+
174178
if not dry_run:
175179
console.print("[red]WARNING: This will modify files. Use --dry-run first![/red]")
176180
console.print("[dim]Press Ctrl+C to abort. Running in 3 seconds...[/dim]")

tests/test_scanner.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,38 @@ def test_stats_command(self, runner, sample_project):
293293
assert "Files scanned" in result.output
294294
assert "Unused exports" in result.output
295295

296+
def test_scan_ignore_option(self, runner, tmp_path):
297+
"""--ignore option should exclude matching files from scan."""
298+
mod = tmp_path / "src" / "mod.ts"
299+
mod.parent.mkdir(parents=True, exist_ok=True)
300+
mod.write_text('export function unusedFunc() { return 1; }\n')
301+
302+
result = runner.invoke(cli, ["-p", str(tmp_path), "-i", "src/", "scan", "--json-output"])
303+
assert result.exit_code == 0
304+
import json
305+
data = json.loads(result.output, strict=False)
306+
assert data["files_scanned"] == 0, "src/ ignored, should have 0 files"
307+
308+
def test_remove_category_filter(self, runner, sample_project):
309+
"""remove --dry-run --category should filter by category."""
310+
result = runner.invoke(cli, ["-p", str(sample_project), "remove", "--dry-run", "-c", "orphaned_css"])
311+
assert result.exit_code == 0
312+
# Should mention orphaned class
313+
assert "orphaned-class" in result.output or "Nothing removable" in result.output
314+
315+
def test_remove_nonexistent_dir(self, runner):
316+
"""remove should give graceful error for nonexistent project dir."""
317+
result = runner.invoke(cli, ["-p", "/nonexistent/test/path", "remove", "--dry-run"])
318+
assert result.exit_code != 0
319+
assert "not found" in result.output
320+
321+
def test_stats_nonexistent_dir(self, runner):
322+
"""stats should handle nonexistent project dir gracefully."""
323+
result = runner.invoke(cli, ["-p", "/nonexistent/stats/path", "stats"])
324+
# Should not crash — scan returns 0 files for nonexistent dir
325+
assert result.exit_code == 0
326+
assert "Files scanned: 0" in result.output
327+
296328
def test_main_module_entry_point(self, runner):
297329
"""Test that python -m deadcode works (__main__ entry point fix)."""
298330
import subprocess

0 commit comments

Comments
 (0)