"""Tests for CLI interface.""" import tempfile from pathlib import Path from unittest.mock import patch from click.testing import CliRunner from src.cli import main class TestMainGroup: """Tests for main CLI group.""" def test_main_help(self): """Test main command shows help.""" runner = CliRunner() result = runner.invoke(main, ["--help"]) assert result.exit_code == 0 assert "Generate conventional commit messages" in result.output def test_main_version(self): """Test version flag works.""" runner = CliRunner() result = runner.invoke(main, ["--version"]) assert result.exit_code == 0 assert "local-commit-message-generator" in result.output class TestGenerateCommand: """Tests for generate command.""" def test_generate_handles_error(self): """Test generate handles errors gracefully.""" runner = CliRunner() with patch('src.generator.generate_commit_message') as mock: mock.side_effect = Exception("No staged changes") result = runner.invoke(main, ["generate"]) assert result.exit_code == 1 class TestInstallHookCommand: """Tests for install-hook command.""" def test_install_hook_no_git_dir(self): """Test install hook fails without .git directory.""" with tempfile.TemporaryDirectory() as tmpdir: runner = CliRunner() result = runner.invoke(main, ["install-hook"], obj={"repo": tmpdir}) assert result.exit_code != 0 assert "not found" in result.output.lower() class TestUninstallHookCommand: """Tests for uninstall-hook command.""" def test_uninstall_hook_not_installed(self): """Test uninstall when hook not installed.""" with tempfile.TemporaryDirectory() as tmpdir: git_dir = Path(tmpdir) / ".git" hooks_dir = git_dir / "hooks" hooks_dir.mkdir(parents=True) runner = CliRunner() result = runner.invoke(main, ["uninstall-hook"], obj={"repo": tmpdir}) assert result.exit_code != 0 class TestConfigCommand: """Tests for config subcommand.""" def test_config_show(self): """Test config show displays configuration.""" runner = CliRunner() result = runner.invoke(main, ["config", "show"]) assert result.exit_code == 0 assert "Current Configuration" in result.output assert "template" in result.output class TestPreviewCommand: """Tests for preview command.""" def test_preview_displays_message(self): """Test preview displays message.""" runner = CliRunner() with patch('src.generator.get_commit_message_preview') as mock: mock.return_value = ("feat: new feature", True) result = runner.invoke(main, ["preview"]) assert result.exit_code == 0 assert "Preview" in result.output assert "feat: new feature" in result.output def test_preview_no_changes(self): """Test preview with no changes.""" runner = CliRunner() with patch('src.generator.get_commit_message_preview') as mock: mock.return_value = ("", False) result = runner.invoke(main, ["preview"]) assert result.exit_code == 0 assert "No staged changes" in result.output class TestStatusCommand: """Tests for status command.""" def test_status_with_changes(self): """Test status shows changes.""" runner = CliRunner() with patch('src.analyzer.ChangeAnalyzer') as mock_analyzer: from src.analyzer import ChangeSet, ChangeType, StagedChange mock_analyzer.return_value.get_staged_changes.return_value = ChangeSet([ StagedChange("src/main.py", ChangeType.ADDED), ]) result = runner.invoke(main, ["status"]) assert result.exit_code == 0 assert "Staged changes" in result.output or "+" in result.output def test_status_no_changes(self): """Test status with no changes.""" runner = CliRunner() with patch('src.analyzer.ChangeAnalyzer') as mock_analyzer: from src.analyzer import ChangeSet mock_analyzer.return_value.get_staged_changes.return_value = ChangeSet([]) result = runner.invoke(main, ["status"]) assert result.exit_code == 0 assert "No staged changes" in result.output