Skip to main content
Glama

MCP Indexer

by gkatechis
test_dependency_analyzer.py9.27 kB
""" Tests for dependency analyzer """ import pytest from mcpindexer.dependency_analyzer import ( DependencyAnalyzer, CrossRepoAnalyzer, Dependency, DependencyGraph ) from mcpindexer.parser import CodeParser # Sample code files for testing SAMPLE_AUTH_CODE = ''' import bcrypt from typing import Optional from .database import get_user from .models.user import User def authenticate(username: str, password: str) -> Optional[User]: user = get_user(username) return user if bcrypt.checkpw(password, user.password) else None ''' SAMPLE_DATABASE_CODE = ''' from sqlalchemy import create_engine from .models.user import User def get_user(username: str): return User.query.filter_by(username=username).first() ''' SAMPLE_USER_MODEL_CODE = ''' from dataclasses import dataclass @dataclass class User: username: str password: str ''' SAMPLE_JS_CODE = ''' const express = require('express'); const { authenticate } = require('./auth'); const User = require('./models/user'); function login(req, res) { const result = authenticate(req.body.username, req.body.password); res.json(result); } ''' class TestDependencyAnalyzer: """Tests for DependencyAnalyzer class""" def setup_method(self): """Set up test fixtures""" self.parser = CodeParser() self.analyzer = DependencyAnalyzer(repo_name="test-repo") def test_analyzer_initialization(self): """Test analyzer initializes correctly""" assert self.analyzer.repo_name == "test-repo" assert len(self.analyzer.file_map) == 0 def test_add_file(self): """Test adding files to analyzer""" parsed = self.parser.parse_file("auth.py", SAMPLE_AUTH_CODE) self.analyzer.add_file(parsed) assert len(self.analyzer.file_map) == 1 assert "auth.py" in self.analyzer.file_map def test_analyze_external_dependencies(self): """Test detection of external dependencies""" parsed = self.parser.parse_file("auth.py", SAMPLE_AUTH_CODE) self.analyzer.add_file(parsed) graph = self.analyzer.analyze() # Should detect external packages (bcrypt, typing) assert len(graph.external_packages) > 0 assert any("bcrypt" in pkg for pkg in graph.external_packages) def test_analyze_internal_dependencies(self): """Test detection of internal dependencies""" parsed = self.parser.parse_file("auth.py", SAMPLE_AUTH_CODE) self.analyzer.add_file(parsed) graph = self.analyzer.analyze() # Should detect internal imports (.database, .models.user) internal_deps = [d for d in graph.dependencies if not d.is_external] assert len(internal_deps) > 0 def test_dependency_graph_structure(self): """Test that dependency graph is properly structured""" parsed = self.parser.parse_file("auth.py", SAMPLE_AUTH_CODE) self.analyzer.add_file(parsed) graph = self.analyzer.analyze() assert isinstance(graph, DependencyGraph) assert isinstance(graph.dependencies, list) assert isinstance(graph.internal_deps, dict) assert isinstance(graph.external_deps, dict) assert isinstance(graph.external_packages, set) def test_multiple_files_analysis(self): """Test analyzing multiple files""" auth_parsed = self.parser.parse_file("auth.py", SAMPLE_AUTH_CODE) db_parsed = self.parser.parse_file("database.py", SAMPLE_DATABASE_CODE) user_parsed = self.parser.parse_file("models/user.py", SAMPLE_USER_MODEL_CODE) self.analyzer.add_file(auth_parsed) self.analyzer.add_file(db_parsed) self.analyzer.add_file(user_parsed) graph = self.analyzer.analyze() assert len(self.analyzer.file_map) == 3 assert len(graph.dependencies) > 0 def test_get_dependencies(self): """Test getting dependencies for a file""" auth_parsed = self.parser.parse_file("auth.py", SAMPLE_AUTH_CODE) self.analyzer.add_file(auth_parsed) graph = self.analyzer.analyze() deps = graph.get_dependencies("auth.py") # auth.py has internal dependencies assert isinstance(deps, list) def test_find_external_calls(self): """Test finding calls to external packages""" parsed = self.parser.parse_file("auth.py", SAMPLE_AUTH_CODE) self.analyzer.add_file(parsed) # Find uses of bcrypt results = self.analyzer.find_external_calls("bcrypt") assert len(results) > 0 assert all(isinstance(r, Dependency) for r in results) def test_get_dependency_stats(self): """Test getting dependency statistics""" auth_parsed = self.parser.parse_file("auth.py", SAMPLE_AUTH_CODE) db_parsed = self.parser.parse_file("database.py", SAMPLE_DATABASE_CODE) self.analyzer.add_file(auth_parsed) self.analyzer.add_file(db_parsed) stats = self.analyzer.get_dependency_stats() assert "total_files" in stats assert "total_dependencies" in stats assert "external_packages" in stats assert stats["total_files"] == 2 def test_javascript_dependencies(self): """Test analyzing JavaScript dependencies""" parsed = self.parser.parse_file("app.js", SAMPLE_JS_CODE) self.analyzer.add_file(parsed) graph = self.analyzer.analyze() # JS require statements may not be parsed yet - just check structure is valid assert isinstance(graph.external_packages, set) assert isinstance(graph.dependencies, list) def test_extract_package_name(self): """Test package name extraction""" # Regular package assert self.analyzer._extract_package_name("express") == "express" # Scoped package assert self.analyzer._extract_package_name("@company/auth") == "@company/auth" # Package with path assert self.analyzer._extract_package_name("lodash/map") == "lodash" # Scoped package with path assert self.analyzer._extract_package_name("@company/auth/lib/utils") == "@company/auth" def test_dependency_object_attributes(self): """Test Dependency object has required attributes""" parsed = self.parser.parse_file("auth.py", SAMPLE_AUTH_CODE) self.analyzer.add_file(parsed) graph = self.analyzer.analyze() if graph.dependencies: dep = graph.dependencies[0] assert hasattr(dep, 'source_file') assert hasattr(dep, 'target_module') assert hasattr(dep, 'is_external') assert hasattr(dep, 'import_type') assert hasattr(dep, 'symbols') class TestCrossRepoAnalyzer: """Tests for CrossRepoAnalyzer class""" def setup_method(self): """Set up test fixtures""" self.parser = CodeParser() self.cross_analyzer = CrossRepoAnalyzer() def test_cross_analyzer_initialization(self): """Test cross-repo analyzer initializes""" assert len(self.cross_analyzer.repo_analyzers) == 0 def test_add_repo(self): """Test adding repository analyzers""" analyzer = DependencyAnalyzer(repo_name="repo1") self.cross_analyzer.add_repo("repo1", analyzer) assert len(self.cross_analyzer.repo_analyzers) == 1 assert "repo1" in self.cross_analyzer.repo_analyzers def test_multiple_repos(self): """Test managing multiple repositories""" analyzer1 = DependencyAnalyzer(repo_name="repo1") analyzer2 = DependencyAnalyzer(repo_name="repo2") self.cross_analyzer.add_repo("repo1", analyzer1) self.cross_analyzer.add_repo("repo2", analyzer2) assert len(self.cross_analyzer.repo_analyzers) == 2 def test_suggest_missing_repos(self): """Test suggesting missing repositories""" # Create analyzer with scoped packages analyzer = DependencyAnalyzer(repo_name="app") code_with_scoped = ''' import { auth } from '@company/auth-service'; import { db } from '@company/database'; ''' parsed = self.parser.parse_file("app.js", code_with_scoped) analyzer.add_file(parsed) self.cross_analyzer.add_repo("app", analyzer) # Suggest missing repos (none indexed yet) suggestions = self.cross_analyzer.suggest_missing_repos(set()) # Should suggest the scoped packages assert len(suggestions) >= 0 # May or may not detect depending on parsing def test_find_cross_repo_dependencies(self): """Test finding dependencies between repos""" analyzer1 = DependencyAnalyzer(repo_name="app") analyzer2 = DependencyAnalyzer(repo_name="auth-service") # Add some files code = 'import express from "express";' parsed = self.parser.parse_file("app.js", code) analyzer1.add_file(parsed) self.cross_analyzer.add_repo("app", analyzer1) self.cross_analyzer.add_repo("auth-service", analyzer2) cross_deps = self.cross_analyzer.find_cross_repo_dependencies() # Should return a list (may be empty for simple test) assert isinstance(cross_deps, list) if __name__ == "__main__": pytest.main([__file__, "-v"])

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/gkatechis/mcpIndexer'

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