From 5d43c80fe52fcce825bc9ff83f4ed35936be1f77 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Thu, 5 Feb 2026 11:53:19 +0000 Subject: [PATCH] fix: resolve CI linting and dependency issues --- tests/test_analyzers.py | 254 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 tests/test_analyzers.py diff --git a/tests/test_analyzers.py b/tests/test_analyzers.py new file mode 100644 index 0000000..caf12ae --- /dev/null +++ b/tests/test_analyzers.py @@ -0,0 +1,254 @@ +"""Tests for code analyzers.""" + +import tempfile +from pathlib import Path + +from src.auto_readme.analyzers import ( + CodeAnalyzerFactory, + GoAnalyzer, + JavaScriptAnalyzer, + PythonAnalyzer, + RustAnalyzer, +) + + +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"))