"""Unit tests for parsers.""" import pytest import os from code_doc_cli.parsers.python_parser import PythonParser from code_doc_cli.parsers.typescript_parser import TypeScriptParser from code_doc_cli.parsers.go_parser import GoParser from code_doc_cli.parsers.registry import ParserRegistry from code_doc_cli.parsers.base import ElementType import tempfile class TestPythonParser: """Tests for Python parser.""" def test_parse_function(self): """Test parsing a Python function.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: f.write(''' def add(a: int, b: int) -> int: """Add two numbers together. Args: a: First number b: Second number Returns: The sum of a and b """ return a + b ''') f.flush() parser = PythonParser(f.name) elements = parser.parse() os.unlink(f.name) assert len(elements) > 0 func_names = [e.name for e in elements] assert "add" in func_names add_elem = next(e for e in elements if e.name == "add") assert add_elem.element_type == ElementType.FUNCTION assert len(add_elem.parameters) == 2 def test_parse_class(self): """Test parsing a Python class.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: f.write(''' class Calculator: """A simple calculator class.""" def __init__(self, initial: int = 0): """Initialize calculator.""" self.memory = initial def multiply(self, x: int, y: int) -> int: """Multiply two numbers.""" return x * y ''') f.flush() parser = PythonParser(f.name) elements = parser.parse() os.unlink(f.name) class_names = [e.name for e in elements] assert "Calculator" in class_names calc_elem = next(e for e in elements if e.name == "Calculator") assert calc_elem.element_type == ElementType.CLASS def test_parse_module(self): """Test parsing module docstring.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: f.write('''"""This is a test module.""" def test_func(): pass ''') f.flush() parser = PythonParser(f.name) elements = parser.parse() os.unlink(f.name) module_elems = [e for e in elements if e.element_type == ElementType.MODULE] assert len(module_elems) == 1 assert "test module" in module_elems[0].description.lower() def test_language_name(self): """Test language name detection.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f: f.write("x = 1\n") f.flush() parser = PythonParser(f.name) os.unlink(f.name) assert parser.get_language_name() == "python" def test_supports_file(self): """Test file extension support.""" assert PythonParser.supports_file("test.py") assert PythonParser.supports_file("test.pyw") assert not PythonParser.supports_file("test.ts") assert not PythonParser.supports_file("test.go") class TestTypeScriptParser: """Tests for TypeScript parser.""" def test_parse_function(self): """Test parsing a TypeScript function.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".ts", delete=False) as f: f.write(''' export function add(a: number, b: number): number { return a + b; } ''') f.flush() parser = TypeScriptParser(f.name) elements = parser.parse() os.unlink(f.name) func_names = [e.name for e in elements if e.element_type == ElementType.FUNCTION] assert "add" in func_names def test_parse_interface(self): """Test parsing a TypeScript interface.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".ts", delete=False) as f: f.write(''' export interface User { id: number; name: string; } ''') f.flush() parser = TypeScriptParser(f.name) elements = parser.parse() os.unlink(f.name) interface_names = [e.name for e in elements if e.element_type == ElementType.INTERFACE] assert "User" in interface_names def test_parse_class(self): """Test parsing a TypeScript class.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".ts", delete=False) as f: f.write(''' export class Calculator { private memory: number; constructor(initial: number = 0) { this.memory = initial; } public multiply(x: number, y: number): number { return x * y; } } ''') f.flush() parser = TypeScriptParser(f.name) elements = parser.parse() os.unlink(f.name) class_names = [e.name for e in elements if e.element_type == ElementType.CLASS] assert "Calculator" in class_names def test_language_name(self): """Test language name detection.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".ts", delete=False) as f: f.write("const x = 1;\n") f.flush() parser = TypeScriptParser(f.name) os.unlink(f.name) assert parser.get_language_name() == "typescript" def test_supports_file(self): """Test file extension support.""" assert TypeScriptParser.supports_file("test.ts") assert TypeScriptParser.supports_file("test.tsx") assert not TypeScriptParser.supports_file("test.py") class TestGoParser: """Tests for Go parser.""" def test_parse_function(self): """Test parsing a Go function.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".go", delete=False) as f: f.write(''' package main func Add(a, b int) int { return a + b } ''') f.flush() parser = GoParser(f.name) elements = parser.parse() os.unlink(f.name) func_names = [e.name for e in elements if e.element_type == ElementType.FUNCTION] assert "Add" in func_names def test_parse_struct(self): """Test parsing a Go struct.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".go", delete=False) as f: f.write(''' package main type Calculator struct { memory int } ''') f.flush() parser = GoParser(f.name) elements = parser.parse() os.unlink(f.name) struct_names = [e.name for e in elements if e.element_type == ElementType.STRUCT] assert "Calculator" in struct_names def test_parse_package(self): """Test parsing package docstring.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".go", delete=False) as f: f.write('''// Package main provides math functions. package main func Add(a, b int) int { return a + b } ''') f.flush() parser = GoParser(f.name) elements = parser.parse() os.unlink(f.name) module_elems = [e for e in elements if e.element_type == ElementType.MODULE] assert len(module_elems) >= 1 def test_language_name(self): """Test language name detection.""" with tempfile.NamedTemporaryFile(mode="w", suffix=".go", delete=False) as f: f.write("package main\n") f.flush() parser = GoParser(f.name) os.unlink(f.name) assert parser.get_language_name() == "go" def test_supports_file(self): """Test file extension support.""" assert GoParser.supports_file("test.go") assert not GoParser.supports_file("test.py") class TestParserRegistry: """Tests for parser registry.""" def test_get_parser_class(self): """Test getting parser class by language.""" assert ParserRegistry.get_parser_class("python") == PythonParser assert ParserRegistry.get_parser_class("py") == PythonParser assert ParserRegistry.get_parser_class("typescript") == TypeScriptParser assert ParserRegistry.get_parser_class("ts") == TypeScriptParser assert ParserRegistry.get_parser_class("go") == GoParser def test_get_language_from_extension(self): """Test language detection from extension.""" assert ParserRegistry.get_language_from_extension("test.py") == "python" assert ParserRegistry.get_language_from_extension("test.ts") == "typescript" assert ParserRegistry.get_language_from_extension("test.go") == "go" def test_get_supported_languages(self): """Test getting supported languages.""" languages = ParserRegistry.get_supported_languages() assert "python" in languages assert "typescript" in languages assert "go" in languages