Files
auto-readme-cli/tests/test_analyzers.py
Developer d8325c4be2
Some checks failed
CI / test (push) Failing after 13s
Fix CI/CD: Add Gitea Actions workflow and fix linting issues
2026-02-05 09:02:49 +00:00

256 lines
8.3 KiB
Python

"""Tests for code analyzers."""
import tempfile
from pathlib import Path
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 # hello and add
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"))