Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a44ea8354d | |||
| 6aab8e86c9 | |||
| a9244d99eb | |||
| 4731f5f19a | |||
| 85ef1f9fa2 | |||
| fe9d0a47cc | |||
| e7247b19ba | |||
| 3f2e056cb0 | |||
| bf420236fa | |||
| 4bbccf751d | |||
| cc2f71932e | |||
| 65b195a77e | |||
| 965adee1a9 | |||
| 68d877050e | |||
| aefc3d1477 |
@@ -22,17 +22,42 @@ jobs:
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e ".[dev]"
|
||||
|
||||
- name: Run tests
|
||||
run: pytest tests/ -v --cov=src --cov-report=term-missing
|
||||
- name: Run pytest
|
||||
run: pytest tests/test_parser.py tests/test_explainer.py tests/test_cli.py tests/conftest.py -v --cov=src/cli_explain_fix --cov-report=term-missing
|
||||
|
||||
- name: Install linting tools
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install ruff
|
||||
run: pip install ruff
|
||||
|
||||
- name: Run linting
|
||||
run: ruff check src/ tests/
|
||||
run: python -m ruff check src/cli_explain_fix/ tests/test_parser.py tests/test_explainer.py tests/test_cli.py tests/conftest.py
|
||||
|
||||
typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install mypy
|
||||
run: pip install mypy
|
||||
|
||||
- name: Run type checking
|
||||
run: python -m mypy src/cli_explain_fix/ tests/test_parser.py tests/test_explainer.py tests/test_cli.py tests/conftest.py
|
||||
|
||||
build:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
103
app/tests/conftest.py
Normal file
103
app/tests/conftest.py
Normal file
@@ -0,0 +1,103 @@
|
||||
"""Test configuration and fixtures."""
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_python_traceback():
|
||||
"""Sample Python traceback for testing."""
|
||||
return '''Traceback (most recent call last):
|
||||
File "/app/main.py", line 10, in <module>
|
||||
import requests
|
||||
ModuleNotFoundError: No module named 'requests'
|
||||
'''
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_python_simple_error():
|
||||
"""Sample simple Python error for testing."""
|
||||
return "ValueError: invalid value for int() with base '10': 'abc'"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_js_error():
|
||||
"""Sample JavaScript error for testing."""
|
||||
return "TypeError: Cannot read property 'map' of undefined"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_go_panic():
|
||||
"""Sample Go panic for testing."""
|
||||
return '''panic: runtime error: invalid memory address or nil pointer dereference
|
||||
goroutine 1 [running]:
|
||||
main.main()
|
||||
/app/main.go:10 +0x20
|
||||
'''
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_rust_panic():
|
||||
"""Sample Rust panic for testing."""
|
||||
return "thread 'main' panicked at 'called Result::unwrap() on an Err value: ParseIntError({invalid digit \"a\" in string}), src/main.rs:10:5"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_json_error():
|
||||
"""Sample JSON parse error for testing."""
|
||||
return "JSONDecodeError: Expecting value: line 1 column 1 (char 0)"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_yaml_error():
|
||||
"""Sample YAML parse error for testing."""
|
||||
return "ParserError: while parsing a block mapping
|
||||
in \"<unicode>\", line 1, column 1
|
||||
did not find expected key"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_cli_error():
|
||||
"""Sample CLI error for testing."""
|
||||
return "error: the following required arguments were not provided:\n --input <file>"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_unknown_error():
|
||||
"""Sample unknown error for testing."""
|
||||
return "Something unexpected happened during processing"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_knowledge_base(tmp_path):
|
||||
"""Create a temporary knowledge base for testing."""
|
||||
kb_dir = tmp_path / "knowledge_base"
|
||||
kb_dir.mkdir()
|
||||
|
||||
errors_file = kb_dir / "errors.yaml"
|
||||
errors_file.write_text('''
|
||||
errors:
|
||||
- error_type: ImportError
|
||||
language: python
|
||||
severity: high
|
||||
what_happened: Python couldn't find and import a module.
|
||||
why_happened: The module doesn't exist or isn't installed.
|
||||
how_to_fix:
|
||||
- Install the package
|
||||
- Check import statement
|
||||
code_snippets: []
|
||||
''')
|
||||
|
||||
patterns_file = kb_dir / "patterns.yaml"
|
||||
patterns_file.write_text('''
|
||||
patterns:
|
||||
python:
|
||||
- pattern: "No module named"
|
||||
error_type: ImportError
|
||||
what_happened: Module not found.
|
||||
why_happened: Module is not installed.
|
||||
how_to_fix:
|
||||
- Install the module
|
||||
severity: high
|
||||
''')
|
||||
|
||||
return str(kb_dir)
|
||||
138
app/tests/test_cli.py
Normal file
138
app/tests/test_cli.py
Normal file
@@ -0,0 +1,138 @@
|
||||
"""Tests for the CLI interface."""
|
||||
|
||||
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
|
||||
126
app/tests/test_explainer.py
Normal file
126
app/tests/test_explainer.py
Normal file
@@ -0,0 +1,126 @@
|
||||
"""Tests for the explainer module."""
|
||||
|
||||
from cli_explain_fix.parser import ErrorParser
|
||||
from cli_explain_fix.explainer import Explainer
|
||||
from cli_explain_fix.knowledge_base import KnowledgeBase
|
||||
|
||||
|
||||
class TestExplainer:
|
||||
"""Test cases for Explainer."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up explainer instance for each test."""
|
||||
self.parser = ErrorParser()
|
||||
self.kb = KnowledgeBase()
|
||||
self.explainer = Explainer(self.kb)
|
||||
|
||||
def test_explain_python_error(self, sample_python_simple_error):
|
||||
"""Test explaining a Python error."""
|
||||
parsed = self.parser.parse(sample_python_simple_error)
|
||||
explanation = self.explainer.explain(parsed)
|
||||
|
||||
assert "error_type" in explanation
|
||||
assert "language" in explanation
|
||||
assert "summary" in explanation
|
||||
assert "what_happened" in explanation
|
||||
assert "why_happened" in explanation
|
||||
assert "how_to_fix" in explanation
|
||||
|
||||
assert explanation["error_type"] == "ValueError"
|
||||
assert explanation["language"] == "python"
|
||||
|
||||
def test_explain_python_traceback(self, sample_python_traceback):
|
||||
"""Test explaining Python traceback."""
|
||||
parsed = self.parser.parse(sample_python_traceback)
|
||||
explanation = self.explainer.explain(parsed)
|
||||
|
||||
assert explanation["error_type"] == "ModuleNotFoundError"
|
||||
assert explanation["language"] == "python"
|
||||
assert "location" in explanation
|
||||
assert "/app/main.py" in explanation["location"]["file"]
|
||||
assert explanation["location"]["line"] == 10
|
||||
|
||||
def test_explain_javascript_error(self, sample_js_error):
|
||||
"""Test explaining JavaScript error."""
|
||||
parsed = self.parser.parse(sample_js_error)
|
||||
explanation = self.explainer.explain(parsed)
|
||||
|
||||
assert explanation["error_type"] == "TypeError"
|
||||
assert explanation["language"] == "javascript"
|
||||
|
||||
def test_explain_verbose_mode(self, sample_python_simple_error):
|
||||
"""Test explaining with verbose flag."""
|
||||
parsed = self.parser.parse(sample_python_simple_error)
|
||||
explanation = self.explainer.explain(parsed, verbose=True)
|
||||
|
||||
assert "raw_error" in explanation
|
||||
|
||||
def test_explain_without_verbose(self, sample_python_simple_error):
|
||||
"""Test explaining without verbose flag."""
|
||||
parsed = self.parser.parse(sample_python_simple_error)
|
||||
explanation = self.explainer.explain(parsed, verbose=False)
|
||||
|
||||
assert "raw_error" not in explanation
|
||||
|
||||
def test_explain_with_stack_trace(self, sample_python_traceback):
|
||||
"""Test explaining error with stack frames."""
|
||||
parsed = self.parser.parse(sample_python_traceback)
|
||||
explanation = self.explainer.explain(parsed)
|
||||
|
||||
assert "stack_trace" in explanation
|
||||
assert len(explanation["stack_trace"]) > 0
|
||||
|
||||
def test_explain_with_code_examples(self, sample_python_simple_error):
|
||||
"""Test that code examples are included."""
|
||||
parsed = self.parser.parse(sample_python_simple_error)
|
||||
explanation = self.explainer.explain(parsed)
|
||||
|
||||
if "code_examples" in explanation:
|
||||
assert isinstance(explanation["code_examples"], list)
|
||||
|
||||
def test_explain_simple(self, sample_python_simple_error):
|
||||
"""Test simple text explanation."""
|
||||
result = self.explainer.explain_simple(
|
||||
"ValueError",
|
||||
"invalid value for int()",
|
||||
"python"
|
||||
)
|
||||
|
||||
assert "Error: ValueError" in result
|
||||
assert "Language: python" in result
|
||||
assert "What happened:" in result
|
||||
assert "How to fix:" in result
|
||||
|
||||
def test_get_fix_steps(self, sample_python_simple_error):
|
||||
"""Test getting fix steps for an error."""
|
||||
parsed = self.parser.parse(sample_python_simple_error)
|
||||
steps = self.explainer.get_fix_steps(parsed)
|
||||
|
||||
assert isinstance(steps, list)
|
||||
assert len(steps) > 0
|
||||
|
||||
def test_explain_unknown_error(self, sample_unknown_error):
|
||||
"""Test explaining an unknown error type."""
|
||||
parsed = self.parser.parse(sample_unknown_error)
|
||||
explanation = self.explainer.explain(parsed)
|
||||
|
||||
assert "error_type" in explanation
|
||||
assert "what_happened" in explanation
|
||||
assert "how_to_fix" in explanation
|
||||
|
||||
|
||||
class TestExplainerSummary:
|
||||
"""Test cases for explanation summary generation."""
|
||||
|
||||
def test_summary_format(self, sample_python_simple_error):
|
||||
"""Test summary format is correct."""
|
||||
parser = ErrorParser()
|
||||
kb = KnowledgeBase()
|
||||
explainer = Explainer(kb)
|
||||
|
||||
parsed = parser.parse(sample_python_simple_error)
|
||||
explanation = explainer.explain(parsed)
|
||||
|
||||
summary = explanation["summary"]
|
||||
assert "ValueError" in summary
|
||||
assert "python" in summary
|
||||
178
app/tests/test_parser.py
Normal file
178
app/tests/test_parser.py
Normal file
@@ -0,0 +1,178 @@
|
||||
"""Tests for the parser module."""
|
||||
|
||||
from cli_explain_fix.parser import ErrorParser, ParsedError
|
||||
|
||||
|
||||
class TestErrorParser:
|
||||
"""Test cases for ErrorParser."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Set up parser instance for each test."""
|
||||
self.parser = ErrorParser()
|
||||
|
||||
def test_detect_language_python_traceback(self, sample_python_traceback):
|
||||
"""Test language detection for Python traceback."""
|
||||
lang = self.parser.detect_language(sample_python_traceback)
|
||||
assert lang == "python"
|
||||
|
||||
def test_detect_language_python_simple(self, sample_python_simple_error):
|
||||
"""Test language detection for simple Python error."""
|
||||
lang = self.parser.detect_language(sample_python_simple_error)
|
||||
assert lang == "python"
|
||||
|
||||
def test_detect_language_javascript(self, sample_js_error):
|
||||
"""Test language detection for JavaScript error."""
|
||||
lang = self.parser.detect_language(sample_js_error)
|
||||
assert lang == "javascript"
|
||||
|
||||
def test_detect_language_go(self, sample_go_panic):
|
||||
"""Test language detection for Go panic."""
|
||||
lang = self.parser.detect_language(sample_go_panic)
|
||||
assert lang == "go"
|
||||
|
||||
def test_detect_language_rust(self, sample_rust_panic):
|
||||
"""Test language detection for Rust panic."""
|
||||
lang = self.parser.detect_language(sample_rust_panic)
|
||||
assert lang == "rust"
|
||||
|
||||
def test_detect_language_json(self, sample_json_error):
|
||||
"""Test language detection for JSON error."""
|
||||
lang = self.parser.detect_language(sample_json_error)
|
||||
assert lang == "json"
|
||||
|
||||
def test_detect_language_yaml(self, sample_yaml_error):
|
||||
"""Test language detection for YAML error."""
|
||||
lang = self.parser.detect_language(sample_yaml_error)
|
||||
assert lang == "yaml"
|
||||
|
||||
def test_detect_language_cli(self, sample_cli_error):
|
||||
"""Test language detection for CLI error."""
|
||||
lang = self.parser.detect_language(sample_cli_error)
|
||||
assert lang == "cli"
|
||||
|
||||
def test_detect_language_unknown(self, sample_unknown_error):
|
||||
"""Test language detection for unknown error."""
|
||||
lang = self.parser.detect_language(sample_unknown_error)
|
||||
assert lang == "unknown"
|
||||
|
||||
def test_parse_python_traceback(self, sample_python_traceback):
|
||||
"""Test parsing Python traceback."""
|
||||
result = self.parser.parse(sample_python_traceback)
|
||||
|
||||
assert isinstance(result, ParsedError)
|
||||
assert result.error_type == "ModuleNotFoundError"
|
||||
assert result.language == "python"
|
||||
assert "requests" in result.message
|
||||
assert result.file_name == "/app/main.py"
|
||||
assert result.line_number == 10
|
||||
assert len(result.stack_frames) > 0
|
||||
|
||||
def test_parse_python_simple(self, sample_python_simple_error):
|
||||
"""Test parsing simple Python error."""
|
||||
result = self.parser.parse(sample_python_simple_error)
|
||||
|
||||
assert isinstance(result, ParsedError)
|
||||
assert result.error_type == "ValueError"
|
||||
assert result.language == "python"
|
||||
assert "invalid value" in result.message
|
||||
|
||||
def test_parse_javascript_error(self, sample_js_error):
|
||||
"""Test parsing JavaScript error."""
|
||||
result = self.parser.parse(sample_js_error)
|
||||
|
||||
assert isinstance(result, ParsedError)
|
||||
assert result.error_type == "TypeError"
|
||||
assert result.language == "javascript"
|
||||
|
||||
def test_parse_go_panic(self, sample_go_panic):
|
||||
"""Test parsing Go panic."""
|
||||
result = self.parser.parse(sample_go_panic)
|
||||
|
||||
assert isinstance(result, ParsedError)
|
||||
assert result.error_type == "panic"
|
||||
assert result.language == "go"
|
||||
|
||||
def test_parse_rust_panic(self, sample_rust_panic):
|
||||
"""Test parsing Rust panic."""
|
||||
result = self.parser.parse(sample_rust_panic)
|
||||
|
||||
assert isinstance(result, ParsedError)
|
||||
assert result.error_type == "panic"
|
||||
assert result.language == "rust"
|
||||
|
||||
def test_parse_json_error(self, sample_json_error):
|
||||
"""Test parsing JSON error."""
|
||||
result = self.parser.parse(sample_json_error)
|
||||
|
||||
assert isinstance(result, ParsedError)
|
||||
assert result.error_type == "JSONParseError"
|
||||
assert result.language == "json"
|
||||
|
||||
def test_parse_yaml_error(self, sample_yaml_error):
|
||||
"""Test parsing YAML error."""
|
||||
result = self.parser.parse(sample_yaml_error)
|
||||
|
||||
assert isinstance(result, ParsedError)
|
||||
assert result.error_type == "YAMLParseError"
|
||||
assert result.language == "yaml"
|
||||
|
||||
def test_parse_cli_error(self, sample_cli_error):
|
||||
"""Test parsing CLI error."""
|
||||
result = self.parser.parse(sample_cli_error)
|
||||
|
||||
assert isinstance(result, ParsedError)
|
||||
assert result.error_type == "GenericError"
|
||||
assert result.language == "cli"
|
||||
|
||||
def test_parse_with_explicit_language(self, sample_python_simple_error):
|
||||
"""Test parsing with explicit language specification."""
|
||||
result = self.parser.parse(sample_python_simple_error, language="python")
|
||||
|
||||
assert result.language == "python"
|
||||
assert result.error_type == "ValueError"
|
||||
|
||||
def test_parse_unknown_error(self, sample_unknown_error):
|
||||
"""Test parsing unknown error returns default."""
|
||||
result = self.parser.parse(sample_unknown_error)
|
||||
|
||||
assert isinstance(result, ParsedError)
|
||||
assert result.error_type == "UnknownError"
|
||||
assert result.language == "unknown"
|
||||
|
||||
def test_parse_empty_input(self):
|
||||
"""Test parsing empty input."""
|
||||
result = self.parser.parse("")
|
||||
|
||||
assert isinstance(result, ParsedError)
|
||||
assert result.error_type == "UnknownError"
|
||||
assert result.message == "Unknown error occurred"
|
||||
|
||||
def test_parsed_error_to_dict(self, sample_python_simple_error):
|
||||
"""Test ParsedError.to_dict() method."""
|
||||
result = self.parser.parse(sample_python_simple_error)
|
||||
data = result.to_dict()
|
||||
|
||||
assert isinstance(data, dict)
|
||||
assert "error_type" in data
|
||||
assert "message" in data
|
||||
assert "language" in data
|
||||
assert "stack_frames" in data
|
||||
|
||||
def test_parse_complex_python_traceback(self):
|
||||
"""Test parsing complex Python traceback with multiple frames."""
|
||||
traceback = '''Traceback (most recent call last):
|
||||
File "app.py", line 5, in <module>
|
||||
main()
|
||||
File "app.py", line 10, in main
|
||||
process()
|
||||
File "processor.py", line 20, in process
|
||||
result = data['key']
|
||||
KeyError: 'key'
|
||||
'''
|
||||
result = self.parser.parse(traceback)
|
||||
|
||||
assert result.error_type == "KeyError"
|
||||
assert result.language == "python"
|
||||
assert result.file_name == "processor.py"
|
||||
assert result.line_number == 20
|
||||
assert len(result.stack_frames) == 3
|
||||
@@ -28,6 +28,7 @@ dependencies = [
|
||||
dev = [
|
||||
"pytest>=7.0.0",
|
||||
"pytest-cov>=4.0.0",
|
||||
"mypy>=1.0.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
@@ -35,3 +36,10 @@ cli-explain-fix = "cli_explain_fix.main:main"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
python_files = ["test_*.py"]
|
||||
python_classes = ["Test*"]
|
||||
python_functions = ["test_*"]
|
||||
addopts = "-v --tb=short"
|
||||
|
||||
Reference in New Issue
Block a user