Skip to main content
Glama
PythonParser.test.ts7.07 kB
// Critical path tests for PythonParser (v1.3) import { describe, it, expect } from 'vitest'; import { PythonParser } from '../../src/lib/PythonParser.js'; describe('PythonParser - Critical Path', () => { describe('Code Detection', () => { it('should detect Python code', () => { const pythonCode = 'def hello():\n print("world")'; expect(PythonParser.isPythonCode(pythonCode)).toBe(true); }); it('should detect Python class', () => { const pythonCode = 'class MyClass:\n pass'; expect(PythonParser.isPythonCode(pythonCode)).toBe(true); }); it('should detect Python import', () => { const pythonCode = 'import os\nfrom sys import path'; expect(PythonParser.isPythonCode(pythonCode)).toBe(true); }); it('should reject non-Python code', () => { const jsCode = 'function hello() { console.log("world"); }'; expect(PythonParser.isPythonCode(jsCode)).toBe(false); }); it('should reject plain text', () => { const text = 'This is just plain text without code'; expect(PythonParser.isPythonCode(text)).toBe(false); }); }); describe('Symbol Finding', () => { it('should find function symbols', async () => { const code = ` def my_function(): return 42 def another_func(x, y): return x + y `; const symbols = await PythonParser.findSymbols(code); expect(symbols.length).toBeGreaterThan(0); const functionNames = symbols.map(s => s.name); expect(functionNames).toContain('my_function'); expect(functionNames).toContain('another_func'); }); it('should find class symbols', async () => { const code = ` class MyClass: def __init__(self): self.value = 0 class AnotherClass: pass `; const symbols = await PythonParser.findSymbols(code); const classSymbols = symbols.filter(s => s.kind === 'class'); expect(classSymbols.length).toBe(2); }); it('should handle empty code', async () => { const symbols = await PythonParser.findSymbols(''); expect(symbols).toEqual([]); }); it('should handle syntax errors gracefully', async () => { const invalidCode = 'def broken(\n # missing closing paren'; await expect(async () => { await PythonParser.findSymbols(invalidCode); }).rejects.toThrow(); }); }); describe('Complexity Analysis', () => { it('should analyze simple function complexity', async () => { const code = ` def simple_func(): return 42 `; const result = await PythonParser.analyzeComplexity(code); expect(result).toHaveProperty('cyclomaticComplexity'); expect(result).toHaveProperty('functions'); expect(result).toHaveProperty('classes'); expect(result.cyclomaticComplexity).toBeGreaterThanOrEqual(1); }); it('should detect multiple functions', async () => { const code = ` def func1(): return 1 def func2(): return 2 def func3(): return 3 `; const result = await PythonParser.analyzeComplexity(code); expect(result.functions.length).toBe(3); }); it('should detect classes', async () => { const code = ` class Class1: pass class Class2: def method(self): pass `; const result = await PythonParser.analyzeComplexity(code); expect(result.classes.length).toBe(2); }); it('should calculate higher complexity for branching', async () => { const complexCode = ` def complex_func(x): if x > 10: for i in range(x): if i % 2 == 0: print(i) return x `; const result = await PythonParser.analyzeComplexity(complexCode); expect(result.cyclomaticComplexity).toBeGreaterThan(1); }); }); describe('Error Handling (CRITICAL)', () => { it('should handle missing Python interpreter', async () => { // This test assumes python3 might not be available // Skip if python3 is available try { await PythonParser.findSymbols('def test(): pass'); // If we get here, python3 is available, skip this test expect(true).toBe(true); } catch (error) { expect(error).toBeDefined(); if (error instanceof Error) { expect(error.message).toContain('Python 3'); } } }); it('should cleanup temp files on success', async () => { const code = 'def test(): pass'; await PythonParser.findSymbols(code); // Check that temp files were cleaned up // (This is implicit - if temp files aren't cleaned, test will pass but system will accumulate files) expect(true).toBe(true); }); it('should cleanup temp files on error', async () => { const invalidCode = 'def broken('; try { await PythonParser.findSymbols(invalidCode); } catch (error) { // Error expected } // Temp files should still be cleaned up expect(true).toBe(true); }); it('should handle very large code files', async () => { // Generate 1000 uniquely named functions const functions = []; for (let i = 0; i < 1000; i++) { functions.push(`def func${i}():\n pass\n`); } const largeCode = functions.join('\n'); const result = await PythonParser.analyzeComplexity(largeCode); expect(result.functions.length).toBe(1000); }, 10000); // 10s timeout for large file }); describe('Special Characters', () => { it('should handle unicode in code', async () => { const code = ` def 한글_함수(): return "한글" `; const symbols = await PythonParser.findSymbols(code); expect(symbols.length).toBeGreaterThan(0); }); it('should handle strings with quotes', async () => { const code = ` def func(): s = "String with \\"quotes\\"" return s `; const symbols = await PythonParser.findSymbols(code); expect(symbols.some(s => s.name === 'func')).toBe(true); }); it('should handle multiline strings', async () => { const code = ` def func(): """ This is a docstring with multiple lines """ return 42 `; const symbols = await PythonParser.findSymbols(code); expect(symbols.some(s => s.name === 'func')).toBe(true); }); }); describe('Concurrent Operations', () => { it('should handle multiple sequential analyses', async () => { // Sequential instead of parallel to avoid temp file conflicts const code1 = 'def func1():\n pass'; const code2 = 'def func2():\n pass'; const code3 = 'def func3():\n pass'; const result1 = await PythonParser.findSymbols(code1); const result2 = await PythonParser.findSymbols(code2); const result3 = await PythonParser.findSymbols(code3); expect(result1.some(s => s.name === 'func1')).toBe(true); expect(result2.some(s => s.name === 'func2')).toBe(true); expect(result3.some(s => s.name === 'func3')).toBe(true); }); }); });

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/su-record/hi-ai'

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