Skip to main content
Glama

Python Code Review MCP Agent

by JJJHoons
test.jsโ€ข16.8 kB
/** * Comprehensive Test Suite for Python Code Review MCP * Tests all analyzer functionality, security detection, and report generation */ import { PythonAnalyzer } from './python-analyzer.js'; import { ReportFormatter } from './report-formatter.js'; class TestRunner { analyzer; formatter; testsPassed = 0; testsTotal = 0; constructor() { this.analyzer = new PythonAnalyzer(); this.formatter = new ReportFormatter(); } assert(condition, message) { this.testsTotal++; if (condition) { this.testsPassed++; console.log(`โœ… ${message}`); } else { console.log(`โŒ ${message}`); } } assertContains(haystack, needle, message) { this.assert(haystack.includes(needle), message); } assertGreaterThan(actual, expected, message) { this.assert(actual > expected, `${message} (${actual} > ${expected})`); } assertLessThan(actual, expected, message) { this.assert(actual < expected, `${message} (${actual} < ${expected})`); } async runAllTests() { console.log('๐Ÿงช Starting Python Code Review MCP Test Suite...\n'); await this.testSecurityVulnerabilities(); await this.testCodeQualityAnalysis(); await this.testReportGeneration(); await this.testEdgeCases(); await this.testRealWorldExamples(); this.printResults(); } async testSecurityVulnerabilities() { console.log('๐Ÿ”’ Testing Security Vulnerability Detection...'); // Test SQL Injection Detection const sqlInjectionCode = ` import sqlite3 def get_user(user_id): conn = sqlite3.connect('db.sqlite') cursor = conn.cursor() # Vulnerable to SQL injection query = "SELECT * FROM users WHERE id = '%s'" % user_id cursor.execute(query) return cursor.fetchone() def get_user_f_string(user_id): cursor.execute(f"SELECT * FROM users WHERE id = {user_id}") def get_user_concat(user_id): cursor.execute("SELECT * FROM users WHERE id = " + str(user_id)) `; const sqlResult = this.analyzer.analyzePythonCode(sqlInjectionCode, 'sql_test.py'); const sqlIssues = sqlResult.issues.filter(i => i.rule.includes('sql-injection')); this.assertGreaterThan(sqlIssues.length, 2, 'Should detect multiple SQL injection vulnerabilities'); this.assert(sqlIssues.some(i => i.severity === 'critical'), 'Should flag string formatting SQL injection as critical'); this.assert(sqlIssues.some(i => i.rule === 'sql-injection-f-string'), 'Should detect f-string SQL injection'); // Test Command Injection Detection const cmdInjectionCode = ` import os import subprocess def dangerous_system_call(user_input): os.system("ls " + user_input) # Vulnerable def dangerous_subprocess(command): subprocess.run(command, shell=True) # Vulnerable def safe_subprocess(command): subprocess.run([command], shell=False) # Safe `; const cmdResult = this.analyzer.analyzePythonCode(cmdInjectionCode, 'cmd_test.py'); const cmdIssues = cmdResult.issues.filter(i => i.rule.includes('command-injection') || i.rule.includes('os-system')); this.assertGreaterThan(cmdIssues.length, 1, 'Should detect command injection vulnerabilities'); this.assert(cmdIssues.some(i => i.severity === 'critical'), 'Should flag os.system as critical'); // Test Hardcoded Secrets Detection const secretsCode = ` # Bad practices DATABASE_PASSWORD = "secret123" API_KEY = "sk-1234567890abcdef" JWT_SECRET = "my-super-secret-key" ACCESS_TOKEN = "bearer-token-here" # Good practice DATABASE_PASSWORD = os.getenv("DB_PASSWORD") `; const secretsResult = this.analyzer.analyzePythonCode(secretsCode, 'secrets_test.py'); const secretIssues = secretsResult.issues.filter(i => i.rule.includes('hardcoded')); this.assertGreaterThan(secretIssues.length, 3, 'Should detect hardcoded secrets'); this.assert(secretIssues.every(i => i.severity === 'high'), 'All hardcoded secrets should be high severity'); // Test Code Injection Detection const codeInjectionCode = ` def dangerous_eval(user_input): result = eval(user_input) # Very dangerous return result def dangerous_exec(code): exec(code) # Also dangerous `; const codeResult = this.analyzer.analyzePythonCode(codeInjectionCode, 'code_injection_test.py'); const codeIssues = codeResult.issues.filter(i => i.rule.includes('code-injection')); this.assertGreaterThan(codeIssues.length, 1, 'Should detect eval and exec usage'); this.assert(codeIssues.every(i => i.severity === 'critical'), 'Code injection should be critical severity'); console.log(); } async testCodeQualityAnalysis() { console.log('๐Ÿ“Š Testing Code Quality Analysis...'); // Test Naming Convention Detection const namingCode = ` class badClassName: # Should be PascalCase pass def BadFunctionName(): # Should be snake_case pass BAD_CONSTANT = "test" # Actually OK for constants good_variable = "test" # OK `; const namingResult = this.analyzer.analyzePythonCode(namingCode, 'naming_test.py'); const namingIssues = namingResult.issues.filter(i => i.rule.includes('naming-convention')); this.assertGreaterThan(namingIssues.length, 1, 'Should detect naming convention violations'); // Test Exception Handling Issues const exceptionCode = ` def bad_exception_handling(): try: risky_operation() except: # Bare except - bad pass try: another_operation() except Exception: # Too broad - medium issue pass def good_exception_handling(): try: risky_operation() except ValueError as e: # Specific exception - good logger.error(f"Value error: {e}") `; const exceptionResult = this.analyzer.analyzePythonCode(exceptionCode, 'exception_test.py'); const exceptionIssues = exceptionResult.issues.filter(i => i.rule.includes('except')); this.assertGreaterThan(exceptionIssues.length, 1, 'Should detect exception handling issues'); this.assert(exceptionIssues.some(i => i.rule === 'bare-except'), 'Should detect bare except clause'); // Test Import Issues const importCode = ` from module import * # Wildcard import - bad import os, sys, json # Multiple imports on one line `; const importResult = this.analyzer.analyzePythonCode(importCode, 'import_test.py'); const importIssues = importResult.issues.filter(i => i.rule.includes('import')); this.assertGreaterThan(importIssues.length, 1, 'Should detect import issues'); // Test Performance Issues const performanceCode = ` def inefficient_loop(items): for i in range(len(items)): # Should use enumerate print(f"Item {i}: {items[i]}") def list_concatenation(): result = [] for item in items: result += [item] # Inefficient, should use extend `; const perfResult = this.analyzer.analyzePythonCode(performanceCode, 'performance_test.py'); const perfIssues = perfResult.issues.filter(i => i.rule.includes('range-len') || i.rule.includes('concatenation')); this.assertGreaterThan(perfIssues.length, 0, 'Should detect performance issues'); console.log(); } async testReportGeneration() { console.log('๐Ÿ“ Testing Report Generation...'); const testCode = ` import sqlite3 import os # Security issue def get_user(user_id): query = "SELECT * FROM users WHERE id = '%s'" % user_id cursor.execute(query) # Quality issue class badClass: # Wrong naming convention def __init__(self): password = "hardcoded123" # Another security issue # Performance issue def process_items(items): for i in range(len(items)): print(items[i]) `; const result = this.analyzer.analyzePythonCode(testCode, 'comprehensive_test.py'); // Test detailed report generation const detailedReport = this.formatter.generateDetailedReport(result); this.assertContains(detailedReport, 'PYTHON CODE REVIEW REPORT', 'Should contain report header'); this.assertContains(detailedReport, 'EXECUTIVE SUMMARY', 'Should contain executive summary'); this.assertContains(detailedReport, 'QUALITY SCORECARD', 'Should contain quality scorecard'); this.assertContains(detailedReport, 'DETAILED ISSUES', 'Should contain detailed issues'); this.assertContains(detailedReport, 'RECOMMENDATIONS', 'Should contain recommendations'); // Test summary report generation const summaryReport = this.formatter.generateSummaryReport(result); this.assertContains(summaryReport, 'PYTHON CODE REVIEW REPORT', 'Summary should contain header'); this.assertContains(summaryReport, 'QUALITY SCORECARD', 'Summary should contain scorecard'); // Test security report generation const securityReport = this.formatter.generateSecurityReport(result); this.assertContains(securityReport, 'SECURITY ANALYSIS REPORT', 'Security report should have security header'); this.assertContains(securityReport, 'Security Score', 'Security report should show security score'); // Test scoring system this.assert(result.codeQualityScore >= 0 && result.codeQualityScore <= 100, 'Code quality score should be 0-100'); this.assert(result.securityScore >= 0 && result.securityScore <= 100, 'Security score should be 0-100'); // With security issues, security score should be lower this.assertLessThan(result.securityScore, 90, 'Security score should reflect detected vulnerabilities'); console.log(); } async testEdgeCases() { console.log('๐Ÿงช Testing Edge Cases...'); // Test empty code const emptyResult = this.analyzer.analyzePythonCode('', 'empty.py'); this.assert(emptyResult.totalLines === 1, 'Empty code should have 1 line'); // Empty string splits to one line this.assert(emptyResult.totalIssues === 0, 'Empty code should have no issues'); // Test single line code const singleLineResult = this.analyzer.analyzePythonCode('print("hello")', 'single.py'); this.assert(singleLineResult.totalLines === 1, 'Single line code should have 1 line'); // Test code with only comments const commentOnlyCode = ` # This is a comment # Another comment """ Multiline comment """ `; const commentResult = this.analyzer.analyzePythonCode(commentOnlyCode, 'comments.py'); this.assert(commentResult.totalIssues === 0, 'Comment-only code should have no issues'); // Test very long function (should trigger complexity warning) const longFunctionCode = ` def very_long_function(): """ This function is intentionally very long """ ${Array(60).fill(' print("line")').join('\n')} `; const longResult = this.analyzer.analyzePythonCode(longFunctionCode, 'long_function.py'); // Note: Our current pattern matching might not catch this perfectly, but let's check this.assertGreaterThan(longResult.totalLines, 50, 'Long function should have many lines'); // Test code with mixed indentation (Python would fail, but we should still analyze) const mixedIndentCode = ` def function(): if True: print("4 spaces") print("tab") # This would cause Python syntax error `; const mixedResult = this.analyzer.analyzePythonCode(mixedIndentCode, 'mixed_indent.py'); this.assert(mixedResult.totalLines > 0, 'Should handle mixed indentation gracefully'); console.log(); } async testRealWorldExamples() { console.log('๐ŸŒ Testing Real-World Examples...'); // Test Flask application with security issues const flaskApp = ` from flask import Flask, request, render_template import sqlite3 import os app = Flask(__name__) app.secret_key = "hardcoded-secret-key" # Security issue @app.route('/user/<user_id>') def get_user(user_id): conn = sqlite3.connect('users.db') cursor = conn.cursor() # SQL Injection vulnerability query = f"SELECT * FROM users WHERE id = {user_id}" cursor.execute(query) user = cursor.fetchone() if user: return render_template('user.html', user=user) else: return "User not found", 404 @app.route('/execute') def execute_command(): cmd = request.args.get('cmd') # Command injection vulnerability os.system(cmd) return "Command executed" if __name__ == '__main__': app.run(debug=True) # Debug mode in production - bad practice `; const flaskResult = this.analyzer.analyzePythonCode(flaskApp, 'flask_app.py'); this.assertGreaterThan(flaskResult.totalIssues, 3, 'Flask app should have multiple security issues'); this.assertGreaterThan(flaskResult.criticalIssues, 0, 'Should have critical security issues'); this.assertLessThan(flaskResult.securityScore, 50, 'Security score should be very low'); // Test Django model with good practices const djangoModel = ` from django.db import models from django.contrib.auth.models import User from django.utils import timezone import uuid class BlogPost(models.Model): """Model for blog posts with proper practices.""" id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) title = models.CharField(max_length=200) content = models.TextField() author = models.ForeignKey(User, on_delete=models.CASCADE) created_at = models.DateTimeField(default=timezone.now) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['-created_at'] verbose_name = 'Blog Post' verbose_name_plural = 'Blog Posts' def __str__(self): return self.title def get_absolute_url(self): return f"/blog/{self.id}/" `; const djangoResult = this.analyzer.analyzePythonCode(djangoModel, 'django_model.py'); this.assertLessThan(djangoResult.totalIssues, 3, 'Well-written Django model should have few issues'); this.assertGreaterThan(djangoResult.codeQualityScore, 80, 'Good code should have high quality score'); this.assertGreaterThan(djangoResult.securityScore, 90, 'Secure code should have high security score'); // Test data processing script with performance issues const dataProcessing = ` import pandas as pd def process_data(filename): # Multiple performance and quality issues data = [] # Reading file line by line instead of using pandas directly with open(filename, 'r') as f: for line in f: data += [line.strip()] # Inefficient list concatenation # Converting to DataFrame inefficiently df = pd.DataFrame() for i in range(len(data)): # Should use enumerate df = df.append({'value': data[i]}, ignore_index=True) return df def analyze_data(df): # TODO: Implement analysis pass # Empty function `; const dataResult = this.analyzer.analyzePythonCode(dataProcessing, 'data_processing.py'); this.assertGreaterThan(dataResult.totalIssues, 2, 'Data processing should have multiple issues'); const todoIssues = dataResult.issues.filter(i => i.rule === 'todo-comment'); this.assertGreaterThan(todoIssues.length, 0, 'Should detect TODO comments'); console.log(); } printResults() { console.log('=' + '='.repeat(50)); console.log(`๐Ÿงช TEST RESULTS: ${this.testsPassed}/${this.testsTotal} tests passed`); if (this.testsPassed === this.testsTotal) { console.log('๐ŸŽ‰ ALL TESTS PASSED! Python Code Review MCP is working perfectly.'); } else { console.log(`โŒ ${this.testsTotal - this.testsPassed} tests failed. Please review the implementation.`); } const successRate = (this.testsPassed / this.testsTotal * 100).toFixed(1); console.log(`๐Ÿ“Š Success Rate: ${successRate}%`); console.log('\n๐ŸŽฏ Test Coverage Summary:'); console.log('โœ… Security vulnerability detection'); console.log('โœ… Code quality analysis'); console.log('โœ… Report generation (detailed, summary, security)'); console.log('โœ… Edge cases and error handling'); console.log('โœ… Real-world application examples'); console.log(); } } // Run tests if this file is executed directly if (import.meta.url === `file://${process.argv[1]}`) { const testRunner = new TestRunner(); testRunner.runAllTests().catch(console.error); } export { TestRunner }; //# sourceMappingURL=test.js.map

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/JJJHoons/python_code_review_mcp'

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