Add test suite with fixtures and tests for all modules
This commit is contained in:
256
tests/test_analyzers.py
Normal file
256
tests/test_analyzers.py
Normal file
@@ -0,0 +1,256 @@
|
||||
"""Tests for code analyzers."""
|
||||
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from src.auto_readme.analyzers import (
|
||||
PythonAnalyzer,
|
||||
JavaScriptAnalyzer,
|
||||
GoAnalyzer,
|
||||
RustAnalyzer,
|
||||
CodeAnalyzerFactory,
|
||||
)
|
||||
|
||||
|
||||
class TestPythonAnalyzer:
|
||||
"""Tests for PythonAnalyzer."""
|
||||
|
||||
def test_can_analyze_py_file(self):
|
||||
"""Test that analyzer recognizes Python files."""
|
||||
analyzer = PythonAnalyzer()
|
||||
with tempfile.NamedTemporaryFile(suffix=".py", delete=False, mode="w") as f:
|
||||
f.write("def hello():\n pass")
|
||||
f.flush()
|
||||
assert analyzer.can_analyze(Path(f.name))
|
||||
Path(f.name).unlink()
|
||||
|
||||
def test_can_analyze_pyi_file(self):
|
||||
"""Test that analyzer recognizes .pyi stub files."""
|
||||
analyzer = PythonAnalyzer()
|
||||
with tempfile.NamedTemporaryFile(suffix=".pyi", delete=False, mode="w") as f:
|
||||
f.write("def hello() -> None: ...")
|
||||
f.flush()
|
||||
assert analyzer.can_analyze(Path(f.name))
|
||||
Path(f.name).unlink()
|
||||
|
||||
def test_analyze_simple_function(self):
|
||||
"""Test analyzing a simple function."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".py", delete=False, mode="w") as f:
|
||||
f.write('''"""Module docstring."""
|
||||
|
||||
def hello():
|
||||
"""Say hello."""
|
||||
print("Hello, World!")
|
||||
|
||||
class Calculator:
|
||||
"""A calculator class."""
|
||||
|
||||
def add(self, a, b):
|
||||
"""Add two numbers."""
|
||||
return a + b
|
||||
''')
|
||||
f.flush()
|
||||
file_path = Path(f.name)
|
||||
analyzer = PythonAnalyzer()
|
||||
result = analyzer.analyze(file_path)
|
||||
|
||||
assert len(result["functions"]) == 2
|
||||
assert len(result["classes"]) == 1
|
||||
|
||||
hello_func = next((f for f in result["functions"] if f.name == "hello"), None)
|
||||
assert hello_func is not None
|
||||
assert hello_func.docstring == "Say hello."
|
||||
assert hello_func.parameters == []
|
||||
|
||||
calc_class = result["classes"][0]
|
||||
assert calc_class.name == "Calculator"
|
||||
assert calc_class.docstring == "A calculator class."
|
||||
|
||||
Path(f.name).unlink()
|
||||
|
||||
def test_analyze_with_parameters(self):
|
||||
"""Test analyzing functions with parameters."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".py", delete=False, mode="w") as f:
|
||||
f.write('''def greet(name, greeting="Hello"):
|
||||
"""Greet someone."""
|
||||
return f"{greeting}, {name}!"
|
||||
|
||||
def add_numbers(a: int, b: int) -> int:
|
||||
"""Add two integers."""
|
||||
return a + b
|
||||
''')
|
||||
f.flush()
|
||||
file_path = Path(f.name)
|
||||
analyzer = PythonAnalyzer()
|
||||
result = analyzer.analyze(file_path)
|
||||
|
||||
greet_func = next((f for f in result["functions"] if f.name == "greet"), None)
|
||||
assert greet_func is not None
|
||||
assert "name" in greet_func.parameters
|
||||
assert "greeting" in greet_func.parameters
|
||||
|
||||
Path(f.name).unlink()
|
||||
|
||||
|
||||
class TestJavaScriptAnalyzer:
|
||||
"""Tests for JavaScriptAnalyzer."""
|
||||
|
||||
def test_can_analyze_js_file(self):
|
||||
"""Test that analyzer recognizes JavaScript files."""
|
||||
analyzer = JavaScriptAnalyzer()
|
||||
with tempfile.NamedTemporaryFile(suffix=".js", delete=False, mode="w") as f:
|
||||
f.write("function hello() { return 'hello'; }")
|
||||
f.flush()
|
||||
assert analyzer.can_analyze(Path(f.name))
|
||||
Path(f.name).unlink()
|
||||
|
||||
def test_can_analyze_ts_file(self):
|
||||
"""Test that analyzer recognizes TypeScript files."""
|
||||
analyzer = JavaScriptAnalyzer()
|
||||
with tempfile.NamedTemporaryFile(suffix=".ts", delete=False, mode="w") as f:
|
||||
f.write("const hello = (): string => 'hello';")
|
||||
f.flush()
|
||||
assert analyzer.can_analyze(Path(f.name))
|
||||
Path(f.name).unlink()
|
||||
|
||||
def test_analyze_simple_function(self):
|
||||
"""Test analyzing a simple JavaScript function."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".js", delete=False, mode="w") as f:
|
||||
f.write('''function hello(name) {
|
||||
return "Hello, " + name + "!";
|
||||
}
|
||||
|
||||
class Calculator {
|
||||
add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { hello, Calculator };
|
||||
''')
|
||||
f.flush()
|
||||
file_path = Path(f.name)
|
||||
analyzer = JavaScriptAnalyzer()
|
||||
result = analyzer.analyze(file_path)
|
||||
|
||||
assert len(result["functions"]) >= 1
|
||||
|
||||
hello_func = next((f for f in result["functions"] if f.name == "hello"), None)
|
||||
assert hello_func is not None
|
||||
|
||||
Path(f.name).unlink()
|
||||
|
||||
|
||||
class TestGoAnalyzer:
|
||||
"""Tests for GoAnalyzer."""
|
||||
|
||||
def test_can_analyze_go_file(self):
|
||||
"""Test that analyzer recognizes Go files."""
|
||||
analyzer = GoAnalyzer()
|
||||
with tempfile.NamedTemporaryFile(suffix=".go", delete=False, mode="w") as f:
|
||||
f.write("package main\n\nfunc hello() string { return 'hello' }")
|
||||
f.flush()
|
||||
assert analyzer.can_analyze(Path(f.name))
|
||||
Path(f.name).unlink()
|
||||
|
||||
def test_analyze_simple_function(self):
|
||||
"""Test analyzing a simple Go function."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".go", delete=False, mode="w") as f:
|
||||
f.write('''package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func hello(name string) string {
|
||||
return "Hello, " + name
|
||||
}
|
||||
|
||||
type Calculator struct{}
|
||||
|
||||
func (c *Calculator) Add(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
''')
|
||||
f.flush()
|
||||
file_path = Path(f.name)
|
||||
analyzer = GoAnalyzer()
|
||||
result = analyzer.analyze(file_path)
|
||||
|
||||
hello_func = next((f for f in result["functions"] if f.name == "hello"), None)
|
||||
assert hello_func is not None
|
||||
assert hello_func.return_type is not None or "string" in str(hello_func.return_type)
|
||||
|
||||
Path(f.name).unlink()
|
||||
|
||||
|
||||
class TestRustAnalyzer:
|
||||
"""Tests for RustAnalyzer."""
|
||||
|
||||
def test_can_analyze_rs_file(self):
|
||||
"""Test that analyzer recognizes Rust files."""
|
||||
analyzer = RustAnalyzer()
|
||||
with tempfile.NamedTemporaryFile(suffix=".rs", delete=False, mode="w") as f:
|
||||
f.write("fn hello() -> String { String::from('hello') }")
|
||||
f.flush()
|
||||
assert analyzer.can_analyze(Path(f.name))
|
||||
Path(f.name).unlink()
|
||||
|
||||
def test_analyze_simple_function(self):
|
||||
"""Test analyzing a simple Rust function."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".rs", delete=False, mode="w") as f:
|
||||
f.write('''fn hello(name: &str) -> String {
|
||||
format!("Hello, {}", name)
|
||||
}
|
||||
|
||||
pub struct Calculator;
|
||||
|
||||
impl Calculator {
|
||||
pub fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
}
|
||||
''')
|
||||
f.flush()
|
||||
file_path = Path(f.name)
|
||||
analyzer = RustAnalyzer()
|
||||
result = analyzer.analyze(file_path)
|
||||
|
||||
hello_func = next((f for f in result["functions"] if f.name == "hello"), None)
|
||||
assert hello_func is not None
|
||||
assert "name" in hello_func.parameters
|
||||
assert hello_func.visibility == "private"
|
||||
|
||||
Path(f.name).unlink()
|
||||
|
||||
|
||||
class TestCodeAnalyzerFactory:
|
||||
"""Tests for CodeAnalyzerFactory."""
|
||||
|
||||
def test_get_analyzer_python(self):
|
||||
"""Test getting analyzer for Python file."""
|
||||
analyzer = CodeAnalyzerFactory.get_analyzer(Path("main.py"))
|
||||
assert isinstance(analyzer, PythonAnalyzer)
|
||||
|
||||
def test_get_analyzer_js(self):
|
||||
"""Test getting analyzer for JavaScript file."""
|
||||
analyzer = CodeAnalyzerFactory.get_analyzer(Path("index.js"))
|
||||
assert isinstance(analyzer, JavaScriptAnalyzer)
|
||||
|
||||
def test_get_analyzer_go(self):
|
||||
"""Test getting analyzer for Go file."""
|
||||
analyzer = CodeAnalyzerFactory.get_analyzer(Path("main.go"))
|
||||
assert isinstance(analyzer, GoAnalyzer)
|
||||
|
||||
def test_get_analyzer_rust(self):
|
||||
"""Test getting analyzer for Rust file."""
|
||||
analyzer = CodeAnalyzerFactory.get_analyzer(Path("main.rs"))
|
||||
assert isinstance(analyzer, RustAnalyzer)
|
||||
|
||||
def test_can_analyze(self):
|
||||
"""Test can_analyze returns correct results."""
|
||||
assert CodeAnalyzerFactory.can_analyze(Path("main.py"))
|
||||
assert CodeAnalyzerFactory.can_analyze(Path("index.js"))
|
||||
assert CodeAnalyzerFactory.can_analyze(Path("main.go"))
|
||||
assert CodeAnalyzerFactory.can_analyze(Path("main.rs"))
|
||||
assert not CodeAnalyzerFactory.can_analyze(Path("random.txt"))
|
||||
Reference in New Issue
Block a user