semantic-prompt-mcp
Version:
MCP server for semantic prompt framework - NLP-inspired adaptive reasoning engine for LLM orchestration
252 lines • 10.1 kB
JavaScript
/**
* 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