diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..2fbfae6 --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,141 @@ +"""Tests for the CLI interface.""" + +import pytest +import sys +from unittest.mock import patch, MagicMock +from typer.testing import CliRunner + +from cli_explain_fix.cli import app + + +class TestCLI: + """Test cases for CLI interface.""" + + def setup_method(self): + """Set up CLI runner for each test.""" + self.runner = CliRunner() + + def test_main_no_input(self): + """Test CLI shows help when no input provided.""" + result = self.runner.invoke(app, ["main"]) + assert result.exit_code == 0 + + def test_main_with_input(self): + """Test CLI with direct input.""" + result = self.runner.invoke(app, ["main", "ValueError: test error"]) + assert result.exit_code == 0 + + def test_main_with_json_flag(self): + """Test CLI with JSON output flag.""" + result = self.runner.invoke(app, ["main", "--json", "ValueError: test error"]) + assert result.exit_code == 0 + + def test_main_with_plain_flag(self): + """Test CLI with plain text output.""" + result = self.runner.invoke(app, ["main", "--plain", "ValueError: test error"]) + assert result.exit_code == 0 + + def test_main_with_language_flag(self): + """Test CLI with explicit language flag.""" + result = self.runner.invoke(app, ["main", "--lang", "python", "ImportError: No module named foo"]) + assert result.exit_code == 0 + + def test_main_with_verbose_flag(self): + """Test CLI with verbose flag.""" + result = self.runner.invoke(app, ["main", "--verbose", "ValueError: test error"]) + assert result.exit_code == 0 + + def test_main_with_no_color_flag(self): + """Test CLI with no-color flag.""" + result = self.runner.invoke(app, ["main", "--no-color", "ValueError: test error"]) + assert result.exit_code == 0 + + def test_list_languages_command(self): + """Test list-languages command.""" + result = self.runner.invoke(app, ["list-languages"]) + assert result.exit_code == 0 + assert "python" in result.output.lower() or "Supported" in result.output + + def test_list_errors_command(self): + """Test list-errors command.""" + result = self.runner.invoke(app, ["list-errors"]) + assert result.exit_code == 0 + + def test_list_errors_with_language_filter(self): + """Test list-errors with language filter.""" + result = self.runner.invoke(app, ["list-errors", "--lang", "python"]) + assert result.exit_code == 0 + + def test_show_config_command(self): + """Test show-config command.""" + result = self.runner.invoke(app, ["show-config"]) + assert result.exit_code == 0 + + def test_main_with_file_input(self, tmp_path): + """Test CLI with file input.""" + test_file = tmp_path / "error.txt" + test_file.write_text("ValueError: test error from file") + + result = self.runner.invoke(app, ["main", "--file", str(test_file)]) + assert result.exit_code == 0 + + def test_main_with_nonexistent_file(self): + """Test CLI with nonexistent file.""" + result = self.runner.invoke(app, ["main", "--file", "/nonexistent/file.txt"]) + assert result.exit_code != 0 + assert "error" in result.output.lower() or "Error" in result.output + + def test_main_with_stdin_input(self): + """Test CLI with stdin input.""" + result = self.runner.invoke(app, ["main"], input="ValueError: stdin error") + assert result.exit_code == 0 + + def test_main_with_theme_option(self): + """Test CLI with theme option.""" + result = self.runner.invoke(app, ["main", "--theme", "dark", "ValueError: test error"]) + assert result.exit_code == 0 + + def test_stdin_takes_precedence_over_args(self): + """Test that stdin is read when provided with args.""" + result = self.runner.invoke(app, ["main", "ValueError: arg input"], input="ValueError: stdin input") + assert result.exit_code == 0 + + +class TestCLIOutputFormats: + """Test CLI output format options.""" + + def setup_method(self): + """Set up CLI runner for each test.""" + self.runner = CliRunner() + + def test_json_output_format(self): + """Test JSON output contains expected fields.""" + result = self.runner.invoke(app, ["main", "--json", "ImportError: No module named foo"]) + assert result.exit_code == 0 + + def test_plain_output_contains_fix_steps(self): + """Test plain output contains fix instructions.""" + result = self.runner.invoke(app, ["main", "--plain", "ValueError: invalid value"]) + assert result.exit_code == 0 + assert "How to fix" in result.output or "fix" in result.output.lower() + + +class TestCLIErrorHandling: + """Test CLI error handling.""" + + def setup_method(self): + """Set up CLI runner for each test.""" + self.runner = CliRunner() + + def test_invalid_file_path(self): + """Test handling of invalid file path.""" + result = self.runner.invoke(app, ["main", "--file", "/path/that/does/not/exist/error.txt"]) + assert result.exit_code != 0 + + def test_empty_file(self, tmp_path): + """Test handling of empty file.""" + test_file = tmp_path / "empty.txt" + test_file.write_text("") + + result = self.runner.invoke(app, ["main", "--file", str(test_file)]) + assert result.exit_code == 0