Skip to content

Commit c5c0bca

Browse files
author
Really Him
committed
chore: refactor test code to reduce file complexity
1 parent 3aedbbe commit c5c0bca

File tree

10 files changed

+843
-799
lines changed

10 files changed

+843
-799
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
"""
2+
Static test data directory for the stats CLI command.
3+
4+
This directory contains a snapshot of the antipasta codebase that was intended
5+
to be used for testing the stats command against real code with varying complexity
6+
metrics. However, it is currently NOT USED in any active tests.
7+
8+
Current status:
9+
- The stats tests use dynamically generated temporary test files via the
10+
temp_project_dir fixture instead of this static data
11+
- This directory could potentially be removed to reduce codebase complexity
12+
- Alternatively, it could be incorporated into tests for more realistic testing
13+
scenarios with actual production code patterns
14+
15+
The fixture mimics the real antipasta project structure (antipasta/cli/,
16+
antipasta/core/, etc.) and provides consistent, reproducible test data for
17+
analyzing code metrics like cyclomatic complexity, LOC, and other metrics.
18+
"""

tests/fixtures/stats_test_data/antipasta/cli/stats.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ def _collect_directory_stats(
491491

492492
# Apply truncation for relative and parent styles (NOT for full)
493493
if path_style != "full" and len(display_path) > 30:
494-
display_path = "..." + display_path[-(30 - 3) :]
494+
display_path = "..." + display_path[-(30 - 3):]
495495

496496
# Remove duplicate counts (a file might be counted multiple times in aggregation)
497497
unique_files = list({id(f): f for f in data["all_files"]}.values())
@@ -748,7 +748,7 @@ def _truncate_path(path: str, max_length: int) -> str:
748748
"""Truncate long paths for display."""
749749
if len(path) <= max_length:
750750
return path
751-
return "..." + path[-(max_length - 3) :]
751+
return "..." + path[-(max_length - 3):]
752752

753753

754754
def _display_json(stats_data: dict[str, Any]) -> None:

tests/unit/cli/stats/__init__.py

Whitespace-only changes.

tests/unit/cli/stats/conftest.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""Shared fixtures and utilities for stats tests."""
2+
3+
import tempfile
4+
from collections.abc import Generator
5+
from pathlib import Path
6+
7+
import pytest
8+
9+
10+
@pytest.fixture
11+
def temp_project_dir() -> Generator[Path, None, None]:
12+
"""Create a temporary project directory with nested Python files."""
13+
with tempfile.TemporaryDirectory() as tmpdir:
14+
base = Path(tmpdir) / "test_project"
15+
base.mkdir()
16+
17+
# Create a nested directory structure with Python files
18+
# Root level
19+
(base / "main.py").write_text("def main():\n pass\n")
20+
(base / "utils.py").write_text("def util():\n return 42\n")
21+
22+
# Level 1 - cli directory
23+
cli_dir = base / "cli"
24+
cli_dir.mkdir()
25+
(cli_dir / "commands.py").write_text(
26+
"def cmd():\n for i in range(10):\n print(i)\n"
27+
)
28+
(cli_dir / "options.py").write_text("OPTIONS = {}\n")
29+
30+
# Level 1 - core directory
31+
core_dir = base / "core"
32+
core_dir.mkdir()
33+
(core_dir / "engine.py").write_text("class Engine:\n def run(self):\n pass\n")
34+
(core_dir / "config.py").write_text("CONFIG = {'debug': True}\n")
35+
36+
# Level 2 - cli/subcommands
37+
sub_dir = cli_dir / "subcommands"
38+
sub_dir.mkdir()
39+
(sub_dir / "analyze.py").write_text(
40+
"def analyze():\n if True:\n return 1\n return 0\n"
41+
)
42+
43+
# Level 2 - core/modules
44+
mod_dir = core_dir / "modules"
45+
mod_dir.mkdir()
46+
(mod_dir / "parser.py").write_text("def parse(data):\n return data\n")
47+
48+
# Level 3 - deeper nesting
49+
deep_dir = mod_dir / "validators"
50+
deep_dir.mkdir()
51+
(deep_dir / "rules.py").write_text("RULES = []\n")
52+
53+
# Level 4 - even deeper
54+
deeper_dir = deep_dir / "builtin"
55+
deeper_dir.mkdir()
56+
(deeper_dir / "basic.py").write_text("def validate():\n pass\n")
57+
58+
yield base
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
"""Tests for unlimited depth traversal feature."""
2+
3+
from pathlib import Path
4+
5+
from click.testing import CliRunner
6+
7+
from antipasta.cli.stats import MAX_DEPTH, stats
8+
9+
10+
class TestUnlimitedDepthFeature:
11+
"""Test suite for TICKET-STATS-001: --depth 0 for unlimited traversal."""
12+
13+
def test_depth_zero_shows_all_levels(self, temp_project_dir: Path) -> None:
14+
"""Test that --depth 0 shows all directory levels."""
15+
runner = CliRunner()
16+
result = runner.invoke(
17+
stats, ["-d", str(temp_project_dir), "--by-directory", "--depth", "0"]
18+
)
19+
20+
assert result.exit_code == 0
21+
# Should show nested directories
22+
assert "modules/validators" in result.output or "validators" in result.output
23+
assert "validators/builtin" in result.output or "builtin" in result.output
24+
25+
def test_depth_one_shows_only_top_level(self, temp_project_dir: Path) -> None:
26+
"""Test that --depth 1 shows only top-level directories."""
27+
runner = CliRunner()
28+
result = runner.invoke(
29+
stats, ["-d", str(temp_project_dir), "--by-directory", "--depth", "1"]
30+
)
31+
32+
assert result.exit_code == 0
33+
output_lines = result.output.split("\n")
34+
35+
# Should show only top-level directories
36+
for line in output_lines:
37+
if "Location" in line or "---" in line or not line.strip():
38+
continue
39+
# Check that no nested paths appear (no slashes in directory names)
40+
if line.strip() and not line.startswith("Found") and not line.startswith("Analyzing"):
41+
parts = line.split()[0]
42+
if parts not in ["test_project", "."]:
43+
assert "/" not in parts, f"Found nested path {parts} in depth=1 output"
44+
45+
def test_depth_two_shows_two_levels(self, temp_project_dir: Path) -> None:
46+
"""Test that --depth 2 shows exactly two levels."""
47+
runner = CliRunner()
48+
result = runner.invoke(
49+
stats, ["-d", str(temp_project_dir), "--by-directory", "--depth", "2"]
50+
)
51+
52+
assert result.exit_code == 0
53+
output_lines = result.output.split("\n")
54+
55+
# Extract directory names from the output
56+
directories = []
57+
for line in output_lines:
58+
if line.strip() and not any(
59+
skip in line
60+
for skip in ["Found", "Analyzing", "CODE METRICS", "Location", "---", "="]
61+
):
62+
parts = line.split()
63+
if parts and any(c.isdigit() for c in line): # Has metrics data
64+
directories.append(parts[0])
65+
66+
# Should show first-level subdirs
67+
assert "cli" in directories
68+
assert "core" in directories
69+
70+
# For depth=2, we should see these directories
71+
# Note: depth=2 shows dirs up to 2 levels deep from base
72+
# The exact subdirectories shown depend on aggregation
73+
74+
def test_max_depth_boundary(self, temp_project_dir: Path) -> None:
75+
"""Test that unlimited depth respects MAX_DEPTH boundary."""
76+
runner = CliRunner()
77+
78+
# depth=0 should be equivalent to depth=MAX_DEPTH
79+
result_zero = runner.invoke(
80+
stats, ["-d", str(temp_project_dir), "--by-directory", "--depth", "0"]
81+
)
82+
83+
result_max = runner.invoke(
84+
stats, ["-d", str(temp_project_dir), "--by-directory", "--depth", str(MAX_DEPTH)]
85+
)
86+
87+
# Both should succeed
88+
assert result_zero.exit_code == 0
89+
assert result_max.exit_code == 0
90+
91+
# Output should be similar (may differ in formatting)
92+
# Count number of directory entries
93+
def count_directories(output: str) -> int:
94+
lines = output.split("\n")
95+
count = 0
96+
for line in lines:
97+
if (
98+
line.strip()
99+
and not any(
100+
skip in line
101+
for skip in ["Found", "Analyzing", "CODE METRICS", "Location", "---", "="]
102+
)
103+
and any(c.isdigit() for c in line)
104+
): # Has metrics data
105+
count += 1
106+
return count
107+
108+
assert count_directories(result_zero.output) == count_directories(result_max.output)
109+
110+
def test_depth_greater_than_max(self, temp_project_dir: Path) -> None:
111+
"""Test that depth > MAX_DEPTH works correctly."""
112+
runner = CliRunner()
113+
result = runner.invoke(
114+
stats, ["-d", str(temp_project_dir), "--by-directory", "--depth", str(MAX_DEPTH + 5)]
115+
)
116+
117+
# Should work without error
118+
assert result.exit_code == 0
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
"""Tests for edge cases and error conditions."""""
2+
3+
from pathlib import Path
4+
5+
from click.testing import CliRunner
6+
7+
from antipasta.cli.stats import stats
8+
9+
10+
class TestEdgeCasesAndErrors:
11+
"""Test edge cases and error conditions."""
12+
13+
def test_invalid_path_style(self) -> None:
14+
"""Test that invalid path style is rejected."""
15+
runner = CliRunner()
16+
17+
result = runner.invoke(stats, ["-d", ".", "--by-directory", "--path-style", "invalid"])
18+
19+
assert result.exit_code != 0
20+
assert "Invalid value" in result.output or "invalid" in result.output.lower()
21+
22+
def test_negative_depth(self, temp_project_dir: Path) -> None:
23+
"""Test that negative depth values are handled."""
24+
runner = CliRunner()
25+
26+
result = runner.invoke(
27+
stats, ["-d", str(temp_project_dir), "--by-directory", "--depth", "-1"]
28+
)
29+
30+
# Should either error or treat as 0/1
31+
# Implementation might vary
32+
assert result.exit_code == 0 or "Invalid" in result.output
33+
34+
def test_very_large_depth(self, temp_project_dir: Path) -> None:
35+
"""Test extremely large depth values."""
36+
runner = CliRunner()
37+
38+
result = runner.invoke(
39+
stats, ["-d", str(temp_project_dir), "--by-directory", "--depth", "999999"]
40+
)
41+
42+
# Should work (capped by actual directory depth)
43+
assert result.exit_code == 0
44+
45+
def test_nonexistent_directory(self) -> None:
46+
"""Test with non-existent directory."""
47+
runner = CliRunner()
48+
49+
result = runner.invoke(
50+
stats, ["-d", "/nonexistent/directory/path", "--by-directory", "--depth", "2"]
51+
)
52+
53+
assert result.exit_code != 0
54+
55+
def test_empty_directory(self, tmp_path: Path) -> None:
56+
"""Test with empty directory."""
57+
runner = CliRunner()
58+
59+
empty_dir = tmp_path / "empty"
60+
empty_dir.mkdir()
61+
62+
result = runner.invoke(stats, ["-d", str(empty_dir), "--by-directory", "--depth", "1"])
63+
64+
# Should handle gracefully
65+
assert "No files found" in result.output or "No analyzable files" in result.output
66+
67+
def test_mixed_file_types(self, tmp_path: Path) -> None:
68+
"""Test directory with non-Python files."""
69+
runner = CliRunner()
70+
71+
mixed_dir = tmp_path / "mixed"
72+
mixed_dir.mkdir()
73+
74+
# Create various file types
75+
(mixed_dir / "test.py").write_text("def hello(): pass")
76+
(mixed_dir / "readme.md").write_text("# README")
77+
(mixed_dir / "data.json").write_text("{}")
78+
79+
result = runner.invoke(stats, ["-d", str(mixed_dir), "--by-directory", "--depth", "1"])
80+
81+
assert result.exit_code == 0
82+
# Should only analyze Python files
83+
assert "1 python files" in result.output.lower()

0 commit comments

Comments
 (0)