"""Tests for reporter modules.""" import json from repohealth.models.file_stats import FileAnalysis from repohealth.models.result import RepositoryResult from repohealth.reporters.html_reporter import HTMLReporter from repohealth.reporters.json_reporter import JSONReporter class TestJSONReporter: """Tests for JSONReporter.""" def setup_method(self): """Set up test fixtures.""" self.reporter = JSONReporter() self.sample_result = RepositoryResult( repository_path="/test/repo", files_analyzed=10, total_commits=100, unique_authors=5, overall_bus_factor=2.5, gini_coefficient=0.35, files=[ { "path": "src/main.py", "total_commits": 20, "num_authors": 2, "author_commits": {"a@x.com": 15, "b@x.com": 5}, "bus_factor": 1.5, "risk_level": "high", "top_author_share": 0.75, "module": "src", "extension": "py" } ], hotspots=[ { "file_path": "src/main.py", "risk_level": "high", "bus_factor": 1.5, "top_author": "a@x.com", "top_author_share": 0.75, "total_commits": 20, "num_authors": 2, "module": "src", "suggestion": "Consider code reviews" } ], suggestions=[ { "file_path": "src/main.py", "current_author": "a@x.com", "suggested_authors": ["b@x.com"], "priority": "high", "reason": "High ownership concentration", "action": "Assign reviews to b@x.com" } ], risk_summary={ "critical": 0, "high": 1, "medium": 3, "low": 6, "percentage_critical": 0.0, "percentage_high": 10.0, "overall_risk": "low" } ) def test_generate_json(self): """Test JSON generation.""" json_output = self.reporter.generate(self.sample_result) assert isinstance(json_output, str) parsed = json.loads(json_output) assert parsed["repository"] == "/test/repo" assert parsed["summary"]["overall_bus_factor"] == 2.5 def test_generate_file_dict(self): """Test file analysis to dictionary conversion.""" analysis = FileAnalysis( path="src/main.py", total_commits=20, author_commits={"a@x.com": 15, "b@x.com": 5}, bus_factor=1.5, risk_level="high", module="src", extension="py" ) file_dict = self.reporter.generate_file_dict(analysis) assert file_dict["path"] == "src/main.py" assert file_dict["total_commits"] == 20 assert file_dict["num_authors"] == 2 assert file_dict["bus_factor"] == 1.5 def test_save_json(self, temp_dir): """Test saving JSON to file.""" output_file = temp_dir / "output.json" self.reporter.save(self.sample_result, str(output_file)) assert output_file.exists() content = json.loads(output_file.read_text()) assert content["repository"] == "/test/repo" def test_indent_parameter(self): """Test JSON indentation.""" reporter_no_indent = JSONReporter(indent=0) json_output = reporter_no_indent.generate(self.sample_result) lines = json_output.strip().split("\n") assert len(lines) <= 2 def test_json_contains_required_fields(self): """Test that JSON output contains all required fields.""" json_output = self.reporter.generate(self.sample_result) parsed = json.loads(json_output) assert "version" in parsed assert "repository" in parsed assert "analyzed_at" in parsed assert "summary" in parsed assert "files" in parsed assert "hotspots" in parsed assert "suggestions" in parsed class TestHTMLReporter: """Tests for HTMLReporter.""" def setup_method(self): """Set up test fixtures.""" self.reporter = HTMLReporter() self.sample_result = RepositoryResult( repository_path="/test/repo", files_analyzed=10, total_commits=100, unique_authors=5, overall_bus_factor=2.5, gini_coefficient=0.35, files=[ { "path": "src/main.py", "total_commits": 20, "num_authors": 2, "author_commits": {"a@x.com": 15, "b@x.com": 5}, "bus_factor": 1.5, "risk_level": "high", "top_author_share": 0.75, "module": "src", "extension": "py" } ], hotspots=[ { "file_path": "src/main.py", "risk_level": "high", "bus_factor": 1.5, "top_author": "a@x.com", "top_author_share": 0.75, "total_commits": 20, "num_authors": 2, "module": "src", "suggestion": "Consider code reviews" } ], suggestions=[ { "file_path": "src/main.py", "current_author": "a@x.com", "suggested_authors": ["b@x.com"], "priority": "high", "reason": "High ownership concentration", "action": "Assign reviews to b@x.com" } ], risk_summary={ "critical": 0, "high": 1, "medium": 3, "low": 6, "percentage_critical": 0.0, "percentage_high": 10.0, "overall_risk": "low" } ) def test_generate_standalone(self): """Test standalone HTML generation.""" html_output = self.reporter.generate_standalone(self.sample_result) assert isinstance(html_output, str) assert "" in html_output.lower() or "" in html_output.lower() assert "" in html_output def test_standalone_contains_summary(self): """Test that standalone HTML contains summary section.""" html_output = self.reporter.generate_standalone(self.sample_result) assert "repository health report" in html_output.lower() def test_standalone_contains_chart_data(self): """Test that standalone HTML includes Chart.js.""" html_output = self.reporter.generate_standalone(self.sample_result) assert "chart.js" in html_output.lower() def test_save_standalone(self, temp_dir): """Test saving standalone HTML to file.""" output_file = temp_dir / "report.html" self.reporter.save_standalone(self.sample_result, str(output_file)) assert output_file.exists() content = output_file.read_text() assert "" in content.lower() or "" in content.lower() def test_generate_charts_data(self): """Test chart data generation.""" charts_data = self.reporter.generate_charts_data(self.sample_result) assert "risk_distribution" in charts_data assert "top_hotspots" in charts_data assert "file_data" in charts_data assert "summary" in charts_data def test_risk_colors_defined(self): """Test that risk colors are properly defined.""" assert "critical" in self.reporter.RISK_COLORS assert "high" in self.reporter.RISK_COLORS assert "medium" in self.reporter.RISK_COLORS assert "low" in self.reporter.RISK_COLORS class TestTerminalReporter: """Tests for TerminalReporter.""" def test_reporter_initialization(self): """Test terminal reporter initialization.""" from repohealth.reporters.terminal import TerminalReporter reporter = TerminalReporter() assert reporter.RISK_COLORS is not None def test_risk_colors_mapping(self): """Test risk color mappings.""" from repohealth.reporters.terminal import TerminalReporter reporter = TerminalReporter() assert reporter.RISK_COLORS["critical"] == "red" assert reporter.RISK_COLORS["high"] == "orange3" assert reporter.RISK_COLORS["medium"] == "yellow" assert reporter.RISK_COLORS["low"] == "green"