"""Tests for CLI interface.""" import os import json import tempfile from pathlib import Path from unittest.mock import patch, MagicMock import pytest from click.testing import CliRunner from repohealth.cli.cli import main, analyze, report, health from repohealth.models.result import RepositoryResult class TestCLI: """Tests for CLI commands.""" def test_main_help(self): """Test main command help.""" runner = CliRunner() result = runner.invoke(main, ["--help"]) assert result.exit_code == 0 assert "RepoHealth CLI" in result.output assert "analyze" in result.output assert "report" in result.output assert "health" in result.output def test_analyze_help(self): """Test analyze command help.""" runner = CliRunner() result = runner.invoke(analyze, ["--help"]) assert result.exit_code == 0 assert "--depth" in result.output assert "--path" in result.output assert "--extensions" in result.output assert "--json" in result.output def test_report_help(self): """Test report command help.""" runner = CliRunner() result = runner.invoke(report, ["--help"]) assert result.exit_code == 0 assert "--format" in result.output assert "--output" in result.output def test_health_help(self): """Test health command help.""" runner = CliRunner() result = runner.invoke(health, ["--help"]) assert result.exit_code == 0 def test_analyze_invalid_repo(self): """Test analyze with invalid repository path.""" runner = CliRunner() result = runner.invoke(analyze, ["/nonexistent/path"]) assert result.exit_code != 0 assert "not a valid Git repository" in result.output def test_health_invalid_repo(self): """Test health with invalid repository path.""" runner = CliRunner() result = runner.invoke(health, ["/nonexistent/path"]) assert result.exit_code != 0 def test_analyze_negative_depth(self): """Test analyze with negative depth option.""" runner = CliRunner() with tempfile.TemporaryDirectory() as tmpdir: result = runner.invoke(analyze, [tmpdir, "--depth", "-5"]) assert result.exit_code != 0 assert "positive integer" in result.output def test_analyze_json_output(self, sample_git_repo, temp_dir): """Test analyze with JSON output.""" runner = CliRunner() result = runner.invoke(analyze, [str(sample_git_repo), "--json"]) assert result.exit_code == 0 output = json.loads(result.output) assert "repository" in output assert "summary" in output assert "files" in output def test_analyze_json_to_file(self, sample_git_repo, temp_dir): """Test analyze saving JSON to file.""" runner = CliRunner() output_file = temp_dir / "output.json" result = runner.invoke( analyze, [str(sample_git_repo), "--output", str(output_file)] ) assert result.exit_code == 0 assert output_file.exists() content = json.loads(output_file.read_text()) assert "repository" in content def test_report_html_output(self, sample_git_repo, temp_dir): """Test report generating HTML output.""" runner = CliRunner() output_file = temp_dir / "report.html" result = runner.invoke( report, [str(sample_git_repo), "--format", "html", "--output", str(output_file)] ) assert result.exit_code == 0 assert output_file.exists() html_content = output_file.read_text() assert "" in html_content assert "Repository Health Report" in html_content def test_health_display(self, sample_git_repo): """Test health command display output.""" runner = CliRunner() result = runner.invoke(health, [str(sample_git_repo)]) assert result.exit_code == 0 assert "Repository Health" in result.output or "Bus Factor" in result.output def test_analyze_with_extensions(self, sample_git_repo): """Test analyze with file extension filter.""" runner = CliRunner() result = runner.invoke( analyze, [str(sample_git_repo), "--extensions", "py", "--json"] ) assert result.exit_code == 0 output = json.loads(result.output) assert output["files_analyzed"] >= 0 def test_analyze_with_depth(self, sample_git_repo): """Test analyze with commit depth limit.""" runner = CliRunner() result = runner.invoke( analyze, [str(sample_git_repo), "--depth", "2", "--json"] ) assert result.exit_code == 0 output = json.loads(result.output) assert "files_analyzed" in output class TestRepoHealthCLI: """Unit tests for RepoHealthCLI class.""" def test_cli_initialization(self): """Test CLI class initialization.""" from repohealth.cli.cli import RepoHealthCLI cli = RepoHealthCLI() assert cli.terminal_reporter is not None assert cli.json_reporter is not None assert cli.html_reporter is not None def test_analyze_repository_result_structure(self, sample_git_repo): """Test that analyze produces valid result structure.""" from repohealth.cli.cli import RepoHealthCLI cli = RepoHealthCLI() result = cli.analyze_repository(str(sample_git_repo)) assert result.repository_path is not None assert isinstance(result.files_analyzed, int) assert isinstance(result.total_commits, int) assert isinstance(result.unique_authors, int) assert isinstance(result.overall_bus_factor, float) assert result.files is not None assert result.risk_summary is not None def test_analyze_repository_min_commits(self, sample_git_repo): """Test analyze with min_commits filter.""" from repohealth.cli.cli import RepoHealthCLI cli = RepoHealthCLI() result_all = cli.analyze_repository( str(sample_git_repo), min_commits=1 ) result_filtered = cli.analyze_repository( str(sample_git_repo), min_commits=100 ) assert result_all.files_analyzed >= result_filtered.files_analyzed