UNPKG

semantic-prompt-mcp

Version:

MCP server for semantic prompt framework - NLP-inspired adaptive reasoning engine for LLM orchestration

252 lines 10.1 kB
/** * Test Suite for Parameter Normalization and Framework Bridge * Tests various input formats to ensure robustness */ import { ParameterNormalizer } from '../utils/parameterNormalizer.js'; import { UnifiedCommandHandler } from '../handlers/commandHandler.js'; import chalk from 'chalk'; // Test data with various problematic formats const testCases = { // XML-like format (problematic format from bug.txt) xmlFormat: { input: { thought: "Test thought", commandSelection: '<parameter name="type">command</parameter><parameter name="command">analyze</parameter>', thoughtNumber: 2, totalThoughts: 3, nextThoughtNeeded: true }, expected: { commandSelection: { type: 'command', command: 'analyze' } } }, // Malformed JSON string malformedJson: { input: { thought: "Test thought", commandSelection: "{'type':'command','command':'build'}", thoughtNumber: 2, totalThoughts: 3, nextThoughtNeeded: "true" }, expected: { commandSelection: { type: 'command', command: 'build' } } }, // Mixed format with nested XML mixedFormat: { input: { thought: "Test thought", commandSelection: '<parameter name="type">command', agentSelection: '{"type": "agents", "agents": ["system-architect", "backend-architect"]}', thoughtNumber: "3", totalThoughts: "4", nextThoughtNeeded: false }, expected: { commandSelection: { type: 'command' }, agentSelection: { type: 'agents', agents: ['system-architect', 'backend-architect'] } } }, // Key-value pairs format keyValueFormat: { input: { thought: "Test thought", commandSelection: "type=command;command=test", thoughtNumber: 2, totalThoughts: 3, nextThoughtNeeded: true }, expected: { commandSelection: { type: 'command', command: 'test' } } }, // Already correct format correctFormat: { input: { thought: "Test thought", commandSelection: { type: 'command', command: 'analyze' }, thoughtNumber: 2, totalThoughts: 3, nextThoughtNeeded: true }, expected: { commandSelection: { type: 'command', command: 'analyze' } } } }; // Framework routing test cases const frameworkTestCases = [ { command: '/sc:analyze', expectedFramework: 'superclaude' }, { command: '/sg:build', expectedFramework: 'supergemini' }, { command: '/sgc:test', expectedFramework: 'supergemini' }, { command: '/u:cleanup', expectedFramework: 'unified' }, { command: '/analyze', expectedFramework: 'supergemini' }, // Default alias { command: 'unknown-command', expectedFramework: 'supergemini' } // Default fallback ]; // Test runner class TestRunner { normalizer; commandHandler; passed = 0; failed = 0; constructor() { this.normalizer = new ParameterNormalizer(); this.commandHandler = new UnifiedCommandHandler(); } // Test parameter normalization testParameterNormalization() { console.log(chalk.blue('\n=== Testing Parameter Normalization ===\n')); for (const [name, testCase] of Object.entries(testCases)) { try { const normalized = this.normalizer.normalizeChainOfThoughtParams(testCase.input); // Check if commandSelection was normalized correctly if (testCase.expected.commandSelection) { const actual = normalized.commandSelection; const expected = testCase.expected.commandSelection; if (JSON.stringify(actual) === JSON.stringify(expected)) { console.log(chalk.green(`✅ ${name}: PASSED`)); this.passed++; } else { console.log(chalk.red(`❌ ${name}: FAILED`)); console.log(` Expected: ${JSON.stringify(expected)}`); console.log(` Actual: ${JSON.stringify(actual)}`); this.failed++; } } // Check if agentSelection was normalized correctly if ('agentSelection' in testCase.expected && testCase.expected.agentSelection) { const actual = normalized.agentSelection; const expected = testCase.expected.agentSelection; if (JSON.stringify(actual) === JSON.stringify(expected)) { console.log(chalk.green(`✅ ${name} (agents): PASSED`)); this.passed++; } else { console.log(chalk.red(`❌ ${name} (agents): FAILED`)); console.log(` Expected: ${JSON.stringify(expected)}`); console.log(` Actual: ${JSON.stringify(actual)}`); this.failed++; } } // Check numeric and boolean normalization if (typeof normalized.thoughtNumber === 'number' && typeof normalized.totalThoughts === 'number' && typeof normalized.nextThoughtNeeded === 'boolean') { console.log(chalk.green(`✅ ${name} (types): PASSED`)); this.passed++; } else { console.log(chalk.red(`❌ ${name} (types): FAILED`)); this.failed++; } } catch (error) { console.log(chalk.red(`❌ ${name}: ERROR - ${error}`)); this.failed++; } } } // Test framework routing testFrameworkRouting() { console.log(chalk.blue('\n=== Testing Framework Routing ===\n')); for (const testCase of frameworkTestCases) { try { const detectedFramework = this.commandHandler.detectFramework(testCase.command); if (detectedFramework === testCase.expectedFramework) { console.log(chalk.green(`✅ ${testCase.command} -> ${detectedFramework}: PASSED`)); this.passed++; } else { console.log(chalk.red(`❌ ${testCase.command}: FAILED`)); console.log(` Expected: ${testCase.expectedFramework}`); console.log(` Actual: ${detectedFramework}`); this.failed++; } } catch (error) { console.log(chalk.red(`❌ ${testCase.command}: ERROR - ${error}`)); this.failed++; } } } // Test edge cases testEdgeCases() { console.log(chalk.blue('\n=== Testing Edge Cases ===\n')); // Test empty input try { const result = this.normalizer.autoNormalize({}); console.log(chalk.green('✅ Empty object handling: PASSED')); this.passed++; } catch { console.log(chalk.red('❌ Empty object handling: FAILED')); this.failed++; } // Test null/undefined try { const result = this.normalizer.autoNormalize(null); console.log(chalk.green('✅ Null handling: PASSED')); this.passed++; } catch { console.log(chalk.red('❌ Null handling: FAILED')); this.failed++; } // Test deeply nested XML try { const nestedXml = '<parameter name="type"><inner>command</inner></parameter>'; const result = this.normalizer.autoNormalize(nestedXml); console.log(chalk.green('✅ Nested XML handling: PASSED')); this.passed++; } catch { console.log(chalk.red('❌ Nested XML handling: FAILED')); this.failed++; } // Test cross-framework calls const canCrossCall = this.commandHandler.canCrossCall('superclaude', 'supergemini'); if (canCrossCall) { console.log(chalk.green('✅ Cross-framework calls: PASSED')); this.passed++; } else { console.log(chalk.red('❌ Cross-framework calls: FAILED')); this.failed++; } } // Run all tests runAll() { console.log(chalk.cyan('\n🧪 Starting Test Suite for Parameter Normalization & Framework Bridge\n')); console.log(chalk.gray('='.repeat(60))); this.testParameterNormalization(); this.testFrameworkRouting(); this.testEdgeCases(); console.log(chalk.gray('\n' + '='.repeat(60))); console.log(chalk.cyan('\n📊 Test Results:\n')); console.log(chalk.green(` Passed: ${this.passed}`)); console.log(chalk.red(` Failed: ${this.failed}`)); const total = this.passed + this.failed; const percentage = total > 0 ? Math.round((this.passed / total) * 100) : 0; if (percentage === 100) { console.log(chalk.green.bold(`\n✨ All tests passed! (${percentage}%)`)); } else if (percentage >= 80) { console.log(chalk.yellow(`\n⚠️ Most tests passed (${percentage}%)`)); } else { console.log(chalk.red(`\n❌ Many tests failed (${percentage}% passed)`)); } // Return exit code return this.failed === 0 ? 0 : 1; } } // Main execution if (import.meta.url === `file://${process.argv[1]}`) { const runner = new TestRunner(); const exitCode = runner.runAll(); process.exit(exitCode); } export { TestRunner }; //# sourceMappingURL=test-parameter-normalization.js.map