From 8fdaa1d1b18b012ad8571933c8a5e480d9a661e6 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Thu, 5 Feb 2026 17:14:11 +0000 Subject: [PATCH] Initial upload: Add repohealth-cli project with CI/CD workflow --- tests/test_reporters.py | 265 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 tests/test_reporters.py diff --git a/tests/test_reporters.py b/tests/test_reporters.py new file mode 100644 index 0000000..c662f77 --- /dev/null +++ b/tests/test_reporters.py @@ -0,0 +1,265 @@ +"""Tests for reporter modules.""" + +import json +import tempfile +from pathlib import Path + +import pytest + +from repohealth.reporters.json_reporter import JSONReporter +from repohealth.reporters.html_reporter import HTMLReporter +from repohealth.models.file_stats import FileAnalysis +from repohealth.models.result import RepositoryResult + + +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_r": "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"