Files
local-llm-prompt-manager/repohealth-cli/tests/test_analyzers.py

268 lines
7.9 KiB
Python

"""Tests for analyzer modules."""
from repohealth.analyzers.bus_factor import BusFactorCalculator
from repohealth.analyzers.risk_analyzer import RiskAnalyzer
from repohealth.models.file_stats import FileAnalysis
class TestBusFactorCalculator:
"""Tests for BusFactorCalculator."""
def setup_method(self):
"""Set up test fixtures."""
self.calculator = BusFactorCalculator()
def test_calculate_gini_equal_distribution(self):
"""Test Gini coefficient with equal distribution."""
values = [10, 10, 10, 10]
gini = self.calculator.calculate_gini(values)
assert gini == 0.0
def test_calculate_gini_unequal_distribution(self):
"""Test Gini coefficient with unequal distribution."""
values = [100, 0, 0, 0]
gini = self.calculator.calculate_gini(values)
assert gini > 0.5
assert gini <= 1.0
def test_calculate_gini_single_value(self):
"""Test Gini coefficient with single value."""
values = [100]
gini = self.calculator.calculate_gini(values)
assert gini == 0.0
def test_calculate_gini_empty_list(self):
"""Test Gini coefficient with empty list."""
gini = self.calculator.calculate_gini([])
assert gini == 0.0
def test_calculate_file_bus_factor_single_author(self):
"""Test bus factor with single author."""
analysis = FileAnalysis(
path="test.py",
total_commits=10,
author_commits={"author@example.com": 10}
)
bus_factor = self.calculator.calculate_file_bus_factor(analysis)
assert bus_factor == 1.0
def test_calculate_file_bus_factor_multiple_authors(self):
"""Test bus factor with multiple authors."""
analysis = FileAnalysis(
path="test.py",
total_commits=10,
author_commits={"a@x.com": 5, "b@x.com": 5}
)
bus_factor = self.calculator.calculate_file_bus_factor(analysis)
assert bus_factor > 1.0
def test_calculate_file_bus_factor_no_commits(self):
"""Test bus factor with no commits."""
analysis = FileAnalysis(
path="test.py",
total_commits=0,
author_commits={}
)
bus_factor = self.calculator.calculate_file_bus_factor(analysis)
assert bus_factor == 1.0
def test_calculate_repository_bus_factor(self):
"""Test repository-level bus factor calculation."""
files = [
FileAnalysis(
path="file1.py",
total_commits=10,
author_commits={"a@x.com": 10}
),
FileAnalysis(
path="file2.py",
total_commits=10,
author_commits={"a@x.com": 5, "b@x.com": 5}
)
]
bus_factor = self.calculator.calculate_repository_bus_factor(files)
assert bus_factor > 1.0
def test_assign_risk_levels(self):
"""Test risk level assignment."""
files = [
FileAnalysis(
path="critical.py",
total_commits=10,
author_commits={"a@x.com": 10}
),
FileAnalysis(
path="low_risk.py",
total_commits=10,
author_commits={"a@x.com": 3, "b@x.com": 3, "c@x.com": 4}
)
]
assigned = self.calculator.assign_risk_levels(files)
assert assigned[0].risk_level == "critical"
assert assigned[1].risk_level == "low"
def test_calculate_repository_gini(self):
"""Test repository-wide Gini coefficient."""
files = [
FileAnalysis(
path="file1.py",
total_commits=10,
author_commits={"a@x.com": 10}
),
FileAnalysis(
path="file2.py",
total_commits=10,
author_commits={"b@x.com": 10}
)
]
gini = self.calculator.calculate_repository_gini(files)
assert gini > 0
class TestRiskAnalyzer:
"""Tests for RiskAnalyzer."""
def setup_method(self):
"""Set up test fixtures."""
self.analyzer = RiskAnalyzer()
def test_identify_hotspots_critical(self):
"""Test hotspot identification for critical files."""
files = [
FileAnalysis(
path="critical.py",
total_commits=10,
author_commits={"a@x.com": 9, "b@x.com": 1},
bus_factor=1.1
),
FileAnalysis(
path="safe.py",
total_commits=10,
author_commits={"a@x.com": 4, "b@x.com": 6},
bus_factor=2.0
)
]
hotspots = self.analyzer.identify_hotspots(files)
assert len(hotspots) >= 1
assert any(h.risk_level == "critical" for h in hotspots)
def test_identify_hotspots_limit(self):
"""Test hotspot limit parameter."""
files = [
FileAnalysis(
path=f"file{i}.py",
total_commits=10,
author_commits={"a@x.com": 9, "b@x.com": 1},
bus_factor=1.1
)
for i in range(25)
]
hotspots = self.analyzer.identify_hotspots(files, limit=10)
assert len(hotspots) == 10
def test_generate_suggestions(self):
"""Test diversification suggestions generation."""
files = [
FileAnalysis(
path="file1.py",
total_commits=10,
author_commits={"a@x.com": 9, "b@x.com": 1}
),
FileAnalysis(
path="file2.py",
total_commits=10,
author_commits={"a@x.com": 5, "b@x.com": 5}
)
]
suggestions = self.analyzer.generate_suggestions(files)
assert len(suggestions) > 0
def test_calculate_risk_summary(self):
"""Test risk summary calculation."""
files = [
FileAnalysis(
path="f1.py",
total_commits=10,
author_commits={"a@x.com": 10},
risk_level="critical"
),
FileAnalysis(
path="f2.py",
total_commits=10,
author_commits={"a@x.com": 8, "b@x.com": 2},
risk_level="high"
),
FileAnalysis(
path="f3.py",
total_commits=10,
author_commits={"a@x.com": 4, "b@x.com": 6},
risk_level="medium"
)
]
summary = self.analyzer.calculate_risk_summary(files)
assert summary["critical"] == 1
assert summary["high"] == 1
assert summary["medium"] == 1
assert "overall_risk" in summary
def test_calculate_risk_summary_empty(self):
"""Test risk summary with empty files."""
summary = self.analyzer.calculate_risk_summary([])
assert summary["overall_risk"] == "unknown"
def test_analyze_module_risk(self):
"""Test module-level risk analysis."""
files = [
FileAnalysis(
path="core/main.py",
total_commits=10,
author_commits={"a@x.com": 10},
module="core",
risk_level="critical"
),
FileAnalysis(
path="core/utils.py",
total_commits=10,
author_commits={"a@x.com": 10},
module="core",
risk_level="critical"
),
FileAnalysis(
path="tests/test.py",
total_commits=10,
author_commits={"a@x.com": 5, "b@x.com": 5},
module="tests",
risk_level="medium"
)
]
module_risk = self.analyzer.analyze_module_risk(files)
assert "core" in module_risk
assert "tests" in module_risk