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