Skip to main content
Glama
test_symbol_operations.py32.3 kB
""" Comprehensive test suite for advanced symbol operations. Tests symbol finding, scope resolution, pattern matching, and relationship analysis with coverage for all major functionality. """ import os import shutil import tempfile import unittest from unittest.mock import MagicMock, patch # Import the module under test from fastapply.symbol_operations import ( AdvancedSymbolOperations, ReferenceAnalysis, ReferenceInfo, ReferenceType, ResolvedScope, SymbolInfo, SymbolScope, SymbolSearchContext, SymbolType, ) class TestAdvancedSymbolOperations(unittest.TestCase): """Test the advanced symbol operations functionality.""" def setUp(self): """Set up test environment.""" self.test_dir = tempfile.mkdtemp() self.original_cwd = os.getcwd() os.chdir(self.test_dir) # Create test files with different symbol types self.create_test_files() # Initialize symbol operations instance self.symbol_ops = AdvancedSymbolOperations() def tearDown(self): """Clean up test environment.""" os.chdir(self.original_cwd) shutil.rmtree(self.test_dir) def create_test_files(self): """Create test files for symbol operations testing.""" # Python file with various symbols with open("test_symbols.py", "w", encoding="utf-8") as f: f.write(''' import os import sys from typing import List, Dict GLOBAL_CONSTANT = "test_value" class TestClass: """A test class for symbol operations.""" def __init__(self, value: int): self.value = value self._private_var = "private" def public_method(self, param: str) -> str: return f"Hello {param}" def _private_method(self) -> None: """Private method for testing.""" pass @property def computed_property(self) -> int: return self.value * 2 def standalone_function(name: str) -> str: return f"Function result: {name}" async def async_function(data: List[str]) -> Dict[str, str]: return {"result": "async"} def helper_function(): pass ''') # JavaScript file with open("app.js", "w", encoding="utf-8") as f: f.write(""" const CONFIG = { apiUrl: "https://api.example.com", timeout: 5000 }; class UserService { constructor(apiUrl) { this.apiUrl = apiUrl; this.users = []; } async getUsers() { const response = await fetch(this.apiUrl + '/users'); return response.json(); } findUserById(id) { return this.users.find(user => user.id === id); } } function formatDate(date) { return date.toISOString(); } let globalVariable = "test"; """) # TypeScript file with open("types.ts", "w", encoding="utf-8") as f: f.write(""" interface User { id: number; name: string; email: string; } type UserRole = 'admin' | 'user' | 'guest'; class AuthService { private token: string; constructor(token: string) { this.token = token; } public authenticate(user: User): boolean { return user.role === 'admin'; } private validateToken(): boolean { return this.token.length > 0; } } const API_ENDPOINT = 'https://api.example.com'; """) def test_symbol_info_creation(self): """Test SymbolInfo dataclass creation and attributes.""" symbol = SymbolInfo( name="test_function", symbol_type=SymbolType.FUNCTION, file_path="test.py", line_number=10, scope=SymbolScope.GLOBAL, documentation="Test function", signature="test_function(param: str) -> str", parameters=["param"], return_type="str", confidence_score=0.95, language="python", ) self.assertEqual(symbol.name, "test_function") self.assertEqual(symbol.symbol_type, SymbolType.FUNCTION) self.assertEqual(symbol.file_path, "test.py") self.assertEqual(symbol.line_number, 10) self.assertEqual(symbol.scope, SymbolScope.GLOBAL) self.assertEqual(symbol.documentation, "Test function") self.assertEqual(symbol.signature, "test_function(param: str) -> str") self.assertEqual(symbol.parameters, ["param"]) self.assertEqual(symbol.return_type, "str") self.assertEqual(symbol.confidence_score, 0.95) self.assertEqual(symbol.language, "python") def test_symbol_search_context_creation(self): """Test SymbolSearchContext creation with various parameters.""" context = SymbolSearchContext( symbol_name="TestClass", symbol_type=SymbolType.CLASS, scope="global", file_path="test.py", language="python", include_imports=True, include_definitions=True, max_results=50, case_sensitive=True, use_semantic_search=True, ) self.assertEqual(context.symbol_name, "TestClass") self.assertEqual(context.symbol_type, SymbolType.CLASS) self.assertEqual(context.scope, "global") self.assertEqual(context.file_path, "test.py") self.assertEqual(context.language, "python") self.assertTrue(context.include_imports) self.assertTrue(context.include_definitions) self.assertEqual(context.max_results, 50) self.assertTrue(context.case_sensitive) self.assertTrue(context.use_semantic_search) def test_find_symbol_basic(self): """Test basic symbol finding functionality.""" # Test finding a class symbol = self.symbol_ops.find_symbol("TestClass", SymbolType.CLASS) self.assertIsInstance(symbol, SymbolInfo) self.assertEqual(symbol.name, "TestClass") self.assertEqual(symbol.symbol_type, SymbolType.CLASS) self.assertIn("test_symbols.py", symbol.file_path) def test_find_symbol_with_scope(self): """Test symbol finding with scope constraints.""" # Test finding a method within class scope symbol = self.symbol_ops.find_symbol("public_method", SymbolType.METHOD, "TestClass") self.assertIsInstance(symbol, SymbolInfo) self.assertEqual(symbol.name, "public_method") self.assertIn("test_symbols.py", symbol.file_path) def test_find_symbols_by_pattern(self): """Test finding symbols using regex patterns.""" # Test pattern matching for functions symbols = self.symbol_ops.find_symbols_by_pattern("def.*function", "python") self.assertIsInstance(symbols, list) self.assertGreater(len(symbols), 0) # All found symbols should be functions (including async functions) for symbol in symbols: self.assertIn(symbol.symbol_type, [SymbolType.FUNCTION, SymbolType.ASYNC_FUNCTION]) def test_resolve_symbol_scope(self): """Test symbol scope resolution.""" context = "def test_function():\n value = GLOBAL_CONSTANT" resolved_scope = self.symbol_ops.resolve_symbol_scope("GLOBAL_CONSTANT", context) self.assertIsInstance(resolved_scope, ResolvedScope) self.assertEqual(resolved_scope.symbol_name, "GLOBAL_CONSTANT") self.assertIn("test_symbols.py", resolved_scope.resolved_path) self.assertEqual(resolved_scope.scope_level, SymbolScope.GLOBAL) def test_get_symbol_references(self): """Test finding symbol references.""" # First, find a symbol symbol = self.symbol_ops.find_symbol("GLOBAL_CONSTANT", SymbolType.CONSTANT) if symbol.file_path: # Only test if symbol was found references = self.symbol_ops.get_symbol_references(symbol) self.assertIsInstance(references, list) # References should not include the definition itself for ref in references: self.assertNotEqual(ref.line_number, symbol.line_number) def test_analyze_symbol_relationships(self): """Test symbol relationship analysis.""" # Find a symbol to analyze symbol = self.symbol_ops.find_symbol("TestClass", SymbolType.CLASS) if symbol.file_path: # Only test if symbol was found relationships = self.symbol_ops.analyze_symbol_relationships(symbol) self.assertIsInstance(relationships, dict) self.assertIn("dependencies", relationships) self.assertIn("dependents", relationships) self.assertIn("related", relationships) # All relationship values should be lists for key, value in relationships.items(): self.assertIsInstance(value, list) def test_multi_language_support(self): """Test symbol operations across different languages.""" # Test JavaScript js_symbols = self.symbol_ops.find_symbols_by_pattern("class", "javascript") self.assertGreater(len(js_symbols), 0) # Test TypeScript ts_symbols = self.symbol_ops.find_symbols_by_pattern("interface", "typescript") self.assertGreater(len(ts_symbols), 0) # Test Python py_symbols = self.symbol_ops.find_symbols_by_pattern("def", "python") self.assertGreater(len(py_symbols), 0) def test_symbol_type_detection(self): """Test automatic symbol type detection.""" # Test function detection symbol = self.symbol_ops.find_symbol("standalone_function", SymbolType.FUNCTION) self.assertEqual(symbol.symbol_type, SymbolType.FUNCTION) # Test class detection symbol = self.symbol_ops.find_symbol("TestClass", SymbolType.CLASS) self.assertEqual(symbol.symbol_type, SymbolType.CLASS) # Test constant detection symbol = self.symbol_ops.find_symbol("GLOBAL_CONSTANT", SymbolType.CONSTANT) self.assertIn(symbol.symbol_type, [SymbolType.CONSTANT, SymbolType.VARIABLE]) def test_async_function_detection(self): """Test async function detection.""" symbol = self.symbol_ops.find_symbol("async_function", SymbolType.ASYNC_FUNCTION) self.assertIn(symbol.symbol_type, [SymbolType.ASYNC_FUNCTION, SymbolType.FUNCTION]) def test_private_method_detection(self): """Test private method detection.""" symbol = self.symbol_ops.find_symbol("_private_method", SymbolType.METHOD) if symbol.file_path: # Only check if found self.assertTrue(symbol.is_private) def test_cache_functionality(self): """Test symbol caching functionality.""" # First search - should populate cache symbol1 = self.symbol_ops.find_symbol("TestClass", SymbolType.CLASS) cache_size_before = len(self.symbol_ops._symbol_cache) # Second search - should use cache symbol2 = self.symbol_ops.find_symbol("TestClass", SymbolType.CLASS) cache_size_after = len(self.symbol_ops._symbol_cache) # Results should be identical self.assertEqual(symbol1.name, symbol2.name) self.assertEqual(symbol1.file_path, symbol2.file_path) # Cache should have been populated self.assertGreaterEqual(cache_size_after, cache_size_before) def test_performance_metrics(self): """Test performance metrics collection.""" metrics = self.symbol_ops.get_performance_metrics() self.assertIsInstance(metrics, dict) self.assertIn("cache_size", metrics) self.assertIn("scope_cache_size", metrics) self.assertIn("cache_hit_rate", metrics) self.assertIn("average_search_time", metrics) self.assertIn("supported_languages", metrics) # Check supported languages supported_langs = metrics["supported_languages"] self.assertIn("python", supported_langs) self.assertIn("javascript", supported_langs) self.assertIn("typescript", supported_langs) def test_cache_clearing(self): """Test cache clearing functionality.""" # Populate cache self.symbol_ops.find_symbol("TestClass", SymbolType.CLASS) self.symbol_ops.resolve_symbol_scope("GLOBAL_CONSTANT", "test context") # Verify cache has content self.assertGreater(len(self.symbol_ops._symbol_cache), 0) self.assertGreater(len(self.symbol_ops._scope_cache), 0) # Clear cache self.symbol_ops.clear_cache() # Verify cache is empty self.assertEqual(len(self.symbol_ops._symbol_cache), 0) self.assertEqual(len(self.symbol_ops._scope_cache), 0) def test_symbol_with_no_matches(self): """Test handling of symbols with no matches.""" symbol = self.symbol_ops.find_symbol("nonexistent_symbol", SymbolType.FUNCTION) self.assertIsInstance(symbol, SymbolInfo) self.assertEqual(symbol.name, "nonexistent_symbol") self.assertEqual(symbol.confidence_score, 0.0) self.assertEqual(symbol.file_path, "") def test_case_sensitive_search(self): """Test case sensitive vs insensitive search.""" # Case sensitive search context_sensitive = SymbolSearchContext(symbol_name="TestClass", case_sensitive=True) # Case insensitive search context_insensitive = SymbolSearchContext(symbol_name="testclass", case_sensitive=False) # Both should find the same symbol due to case insensitivity handling symbol1 = self.symbol_ops.find_symbol(context_sensitive.symbol_name, context_sensitive.symbol_type) symbol2 = self.symbol_ops.find_symbol(context_insensitive.symbol_name, context_insensitive.symbol_type) if symbol1.file_path and symbol2.file_path: self.assertEqual(symbol1.file_path, symbol2.file_path) def test_error_handling(self): """Test error handling for various edge cases.""" # Test with empty symbol name symbol = self.symbol_ops.find_symbol("", SymbolType.FUNCTION) self.assertIsInstance(symbol, SymbolInfo) # Test with invalid file path symbol = self.symbol_ops.find_symbol("test", SymbolType.FUNCTION, scope="invalid_scope") self.assertIsInstance(symbol, SymbolInfo) # Test with non-existent language symbols = self.symbol_ops.find_symbols_by_pattern("test", "nonexistent_lang") self.assertIsInstance(symbols, list) @patch("fastapply.symbol_operations.RipgrepIntegration") def test_ripgrep_integration_failure(self, mock_ripgrep): """Test behavior when ripgrep integration fails.""" # Make ripgrep raise an exception mock_ripgrep_instance = MagicMock() mock_ripgrep_instance.search_files.side_effect = Exception("Ripgrep failed") mock_ripgrep.return_value = mock_ripgrep_instance # Recreate symbol ops with mocked ripgrep symbol_ops = AdvancedSymbolOperations() # Should handle the failure gracefully symbol = symbol_ops.find_symbol("test", SymbolType.FUNCTION) self.assertIsInstance(symbol, SymbolInfo) def test_symbol_metadata_enrichment(self): """Test that symbol metadata is properly enriched.""" symbol = self.symbol_ops.find_symbol("TestClass", SymbolType.CLASS) if symbol.file_path: # Only test if found self.assertIsInstance(symbol.metadata, dict) self.assertIn("language", symbol.metadata) self.assertEqual(symbol.language, "python") def test_symbol_confidence_scoring(self): """Test confidence scoring for different symbol matches.""" # Test exact match exact_symbol = self.symbol_ops.find_symbol("TestClass", SymbolType.CLASS) # Test semantic match semantic_symbol = self.symbol_ops.find_symbol("test_class", SymbolType.CLASS) # Exact matches should have higher confidence if exact_symbol.file_path and semantic_symbol.file_path: self.assertGreaterEqual(exact_symbol.confidence_score, semantic_symbol.confidence_score) class TestSymbolInfo(unittest.TestCase): """Test SymbolInfo dataclass functionality.""" def test_default_values(self): """Test SymbolInfo default values.""" symbol = SymbolInfo(name="test", symbol_type=SymbolType.FUNCTION, file_path="test.py", line_number=1) self.assertEqual(symbol.column_number, 0) self.assertEqual(symbol.scope, SymbolScope.GLOBAL) self.assertIsNone(symbol.parent_symbol) self.assertIsNone(symbol.documentation) self.assertEqual(symbol.parameters, []) self.assertEqual(symbol.decorators, []) self.assertFalse(symbol.is_async) self.assertFalse(symbol.is_private) self.assertFalse(symbol.is_protected) self.assertFalse(symbol.is_static) self.assertFalse(symbol.is_abstract) self.assertEqual(symbol.confidence_score, 1.0) self.assertEqual(symbol.language, "python") self.assertEqual(symbol.metadata, {}) def test_comprehensive_symbol_info(self): """Test SymbolInfo with all fields populated.""" symbol = SymbolInfo( name="complex_function", symbol_type=SymbolType.ASYNC_FUNCTION, file_path="complex.py", line_number=42, column_number=8, scope=SymbolScope.CLASS, parent_symbol="ComplexClass", documentation="A complex async function", signature="async complex_function(param: List[str]) -> Dict[str, Any]", return_type="Dict[str, Any]", parameters=["param"], decorators=["@staticmethod", "@timer"], is_async=True, is_private=False, is_protected=False, is_static=True, is_abstract=False, confidence_score=0.95, language="python", metadata={"complexity": "high", "lines_of_code": 150}, ) self.assertEqual(symbol.name, "complex_function") self.assertEqual(symbol.symbol_type, SymbolType.ASYNC_FUNCTION) self.assertTrue(symbol.is_async) self.assertTrue(symbol.is_static) self.assertEqual(symbol.decorators, ["@staticmethod", "@timer"]) self.assertEqual(symbol.metadata["complexity"], "high") class TestResolvedScope(unittest.TestCase): """Test ResolvedScope functionality.""" def test_resolved_scope_creation(self): """Test ResolvedScope creation with all fields.""" context = {"file": "test.py", "line": 10} alternatives = [SymbolInfo("alt1", SymbolType.VARIABLE, "alt.py", 1), SymbolInfo("alt2", SymbolType.VARIABLE, "alt2.py", 2)] resolved = ResolvedScope( symbol_name="test_symbol", resolved_path="test.py:10", scope_level=SymbolScope.FUNCTION, context=context, confidence=0.85, alternative_matches=alternatives, ) self.assertEqual(resolved.symbol_name, "test_symbol") self.assertEqual(resolved.resolved_path, "test.py:10") self.assertEqual(resolved.scope_level, SymbolScope.FUNCTION) self.assertEqual(resolved.context, context) self.assertEqual(resolved.confidence, 0.85) self.assertEqual(len(resolved.alternative_matches), 2) class TestReferenceAnalysis(unittest.TestCase): """Test the reference analysis functionality.""" def setUp(self): """Set up test environment.""" self.test_dir = tempfile.mkdtemp() self.original_cwd = os.getcwd() os.chdir(self.test_dir) # Create test files with reference patterns self.create_test_files() # Initialize reference analysis instance self.ref_analysis = ReferenceAnalysis() def tearDown(self): """Clean up test environment.""" os.chdir(self.original_cwd) shutil.rmtree(self.test_dir) def create_test_files(self): """Create test files for reference analysis testing.""" # Python file with various references with open("test_references.py", "w", encoding="utf-8") as f: f.write(''' import os import sys from typing import List, Dict GLOBAL_CONSTANT = "test_value" class TestClass: """A test class for reference analysis.""" def __init__(self, value: int): self.value = value self._private_var = "private" def public_method(self, param: str) -> str: return f"Hello {param}" def _private_method(self) -> None: """Private method for testing.""" pass @property def computed_property(self) -> int: return self.value * 2 def standalone_function(name: str) -> str: return f"Function result: {name}" def function_with_references(): # Reference to global constant value = GLOBAL_CONSTANT # Reference to class obj = TestClass(42) # Reference to method result = obj.public_method("test") # Reference to standalone function output = standalone_function("reference") return result + output class SubClass(TestClass): """Subclass for inheritance testing.""" def overridden_method(self): # Reference to parent method return super().public_method("subclass") def new_method(self): # Reference to global function return standalone_function("new") ''') # JavaScript file with open("app.js", "w", encoding="utf-8") as f: f.write(""" const CONFIG = { apiUrl: "https://api.example.com", timeout: 5000 }; class UserService { constructor(apiUrl) { this.apiUrl = apiUrl; this.users = []; } async getUsers() { const response = await fetch(this.apiUrl + '/users'); return response.json(); } findUserById(id) { return this.users.find(user => user.id === id); } } function formatDate(date) { return date.toISOString(); } function processData() { // Reference to global constant const url = CONFIG.apiUrl; // Reference to class const service = new UserService(url); // Reference to method const users = service.getUsers(); // Reference to function const formatted = formatDate(new Date()); return { users, formatted }; } """) def test_reference_info_creation(self): """Test ReferenceInfo dataclass creation.""" ref_info = ReferenceInfo( symbol_name="test_function", reference_type=ReferenceType.CALL, file_path="test.py", line_number=15, context="function call", confidence_score=0.95, language="python", scope=SymbolScope.GLOBAL ) self.assertEqual(ref_info.symbol_name, "test_function") self.assertEqual(ref_info.file_path, "test.py") self.assertEqual(ref_info.line_number, 15) self.assertEqual(ref_info.reference_type, ReferenceType.CALL) self.assertEqual(ref_info.scope, SymbolScope.GLOBAL) self.assertEqual(ref_info.confidence_score, 0.95) self.assertEqual(ref_info.language, "python") self.assertEqual(ref_info.context, "function call") def test_analyze_symbol_references_basic(self): """Test basic symbol reference analysis.""" # Find a symbol first symbol_ops = AdvancedSymbolOperations() symbol = symbol_ops.find_symbol("GLOBAL_CONSTANT", SymbolType.CONSTANT) if symbol.file_path: # Only test if symbol was found references = self.ref_analysis.analyze_symbol_references(symbol) self.assertIsInstance(references, list) # Should find at least the definition and some references self.assertGreaterEqual(len(references), 1) # Check reference structure for ref in references: self.assertIsInstance(ref, ReferenceInfo) self.assertIsInstance(ref.reference_type, ReferenceType) self.assertIsInstance(ref.scope, SymbolScope) def test_reference_type_classification(self): """Test reference type classification.""" symbol = SymbolInfo("TestClass", SymbolType.CLASS, "test_references.py", 8) references = self.ref_analysis.analyze_symbol_references(symbol) if references: # Should have different reference types reference_types = {ref.reference_type for ref in references} self.assertGreater(len(reference_types), 0) # Check that types are valid ReferenceType enum values for ref_type in reference_types: self.assertIn(ref_type, ReferenceType) def test_get_symbol_dependencies(self): """Test symbol dependency analysis.""" symbol = SymbolInfo("function_with_references", SymbolType.FUNCTION, "test_references.py", 40) dependencies = self.ref_analysis.get_symbol_dependencies(symbol) self.assertIsInstance(dependencies, dict) self.assertIn("direct", dependencies) self.assertIn("transitive", dependencies) # Should have direct dependencies direct_deps = dependencies["direct"] self.assertIsInstance(direct_deps, list) def test_analyze_refactoring_safety(self): """Test refactoring safety analysis.""" symbol = SymbolInfo("GLOBAL_CONSTANT", SymbolType.CONSTANT, "test_references.py", 6) safety_analysis = self.ref_analysis.analyze_refactoring_safety(symbol) self.assertIsInstance(safety_analysis, dict) self.assertIn("is_safe_to_rename", safety_analysis) self.assertIn("impact_score", safety_analysis) self.assertIn("risk_factors", safety_analysis) self.assertIn("affected_files", safety_analysis) self.assertIn("reference_count", safety_analysis) # Impact score should be between 0 and 1 self.assertGreaterEqual(safety_analysis["impact_score"], 0.0) self.assertLessEqual(safety_analysis["impact_score"], 1.0) def test_get_reference_statistics(self): """Test reference statistics.""" symbol = SymbolInfo("TestClass", SymbolType.CLASS, "test_references.py", 8) stats = self.ref_analysis.get_reference_statistics(symbol) self.assertIsInstance(stats, dict) self.assertIn("total_references", stats) self.assertIn("references_by_type", stats) self.assertIn("references_by_file", stats) self.assertIn("references_by_scope", stats) self.assertIn("average_confidence", stats) self.assertIn("reference_density", stats) # Total references should be non-negative self.assertGreaterEqual(stats["total_references"], 0) # Average confidence should be between 0 and 1 self.assertGreaterEqual(stats["average_confidence"], 0.0) self.assertLessEqual(stats["average_confidence"], 1.0) def test_find_unused_symbols(self): """Test unused symbol detection.""" unused_symbols = self.ref_analysis.find_unused_symbols("test_references.py", "python") self.assertIsInstance(unused_symbols, list) # All returned items should be SymbolInfo objects for symbol in unused_symbols: self.assertIsInstance(symbol, SymbolInfo) def test_cross_language_reference_analysis(self): """Test reference analysis across different languages.""" # Test Python python_symbol = SymbolInfo("formatDate", SymbolType.FUNCTION, "app.js", 25) python_refs = self.ref_analysis.analyze_symbol_references(python_symbol) # Test JavaScript js_symbol = SymbolInfo("TestClass", SymbolType.CLASS, "test_references.py", 8) js_refs = self.ref_analysis.analyze_symbol_references(js_symbol) # Should work for both languages self.assertIsInstance(python_refs, list) self.assertIsInstance(js_refs, list) def test_reference_pattern_extraction(self): """Test that reference patterns are correctly extracted.""" # This tests the internal pattern matching logic symbol = SymbolInfo("UserService", SymbolType.CLASS, "app.js", 10) references = self.ref_analysis.analyze_symbol_references(symbol) if references: # Check that references have proper context for ref in references: self.assertIsInstance(ref.line_content, str) self.assertIsInstance(ref.context, str) self.assertGreater(ref.confidence_score, 0.0) def test_reference_scope_detection(self): """Test that reference scopes are correctly detected.""" symbol = SymbolInfo("computed_property", SymbolType.PROPERTY, "test_references.py", 30) references = self.ref_analysis.analyze_symbol_references(symbol) if references: # Should have different scopes scopes = {ref.scope for ref in references} self.assertGreater(len(scopes), 0) # All scopes should be valid SymbolScope enum values for scope in scopes: self.assertIn(scope, SymbolScope) def test_reference_confidence_scoring(self): """Test that reference confidence scores are reasonable.""" symbol = SymbolInfo("public_method", SymbolType.METHOD, "test_references.py", 18) references = self.ref_analysis.analyze_symbol_references(symbol) if references: for ref in references: # Confidence should be between 0 and 1 self.assertGreaterEqual(ref.confidence_score, 0.0) self.assertLessEqual(ref.confidence_score, 1.0) def test_error_handling_invalid_symbol(self): """Test error handling for invalid symbols.""" symbol = SymbolInfo("nonexistent_symbol", SymbolType.FUNCTION, "nonexistent.py", 1) # Should handle gracefully without exceptions references = self.ref_analysis.analyze_symbol_references(symbol) self.assertIsInstance(references, list) dependencies = self.ref_analysis.get_symbol_dependencies(symbol) self.assertIsInstance(dependencies, dict) safety = self.ref_analysis.analyze_refactoring_safety(symbol) self.assertIsInstance(safety, dict) stats = self.ref_analysis.get_reference_statistics(symbol) self.assertIsInstance(stats, dict) def test_large_file_performance(self): """Test performance with larger files.""" # Create a larger test file with open("large_test.py", "w", encoding="utf-8") as f: f.write(""" # Large test file for performance testing import os import sys import json from typing import List, Dict, Any LARGE_CONSTANT = "large_value" class LargeClass: def __init__(self): self.data = [] def method1(self): pass def method2(self): pass def method3(self): pass def complex_method(self): result = LARGE_CONSTANT for i in range(100): result += str(i) return result def large_function(): return LARGE_CONSTANT + " processed" # Multiple references to test performance def test_function1(): return LARGE_CONSTANT def test_function2(): return LARGE_CONSTANT def test_function3(): return LARGE_CONSTANT def test_function4(): return LARGE_CONSTANT def test_function5(): return LARGE_CONSTANT """) # Test with a symbol from the large file symbol = SymbolInfo("LARGE_CONSTANT", SymbolType.CONSTANT, "large_test.py", 8) # Should still perform reasonably references = self.ref_analysis.analyze_symbol_references(symbol) self.assertIsInstance(references, list) # Should find multiple references self.assertGreater(len(references), 3) def test_reference_metadata_enrichment(self): """Test that reference metadata is properly enriched.""" symbol = SymbolInfo("UserService", SymbolType.CLASS, "app.js", 10) references = self.ref_analysis.analyze_symbol_references(symbol) if references: for ref in references: self.assertIsInstance(ref.metadata, dict) self.assertIn("language", ref.metadata) self.assertEqual(ref.language, "javascript") if __name__ == "__main__": unittest.main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/betmoar/FastApply-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server