test-enhanced-adapters.js•24.8 kB
#!/usr/bin/env node
/**
* Enhanced Subject Adapters Test Suite
* @description Comprehensive testing for PhysicsAdapter, ChemistryAdapter, HistoryAdapter, and AdapterFactory
* @version 5.0.0-alpha
*/
import {
BaseAdapter,
PhysicsAdapter,
ChemistryAdapter,
HistoryAdapter,
AdapterFactory,
adapterFactory,
createOptimalAdapter,
generateEnhancedContent
} from '../../src/content-generation/index.js';
class EnhancedAdaptersTestSuite {
constructor() {
this.totalTests = 0;
this.passedTests = 0;
this.failedTests = 0;
this.testResults = [];
this.startTime = Date.now();
}
/**
* Run all enhanced adapter tests
*/
async runAllTests() {
console.log('🧪 Enhanced Subject Adapters Test Suite v5.0.0-alpha');
console.log('=' .repeat(60));
try {
// Test individual enhanced adapters
await this.testPhysicsAdapter();
await this.testChemistryAdapter();
await this.testHistoryAdapter();
// Test adapter factory system
await this.testAdapterFactory();
await this.testAdapterSelection();
await this.testEnhancedContentGeneration();
// Test integration and performance
await this.testIntegrationScenarios();
await this.testPerformanceMetrics();
// Test fallback mechanisms
await this.testFallbackBehavior();
this.printTestSummary();
} catch (error) {
console.error('❌ Test suite execution failed:', error);
process.exit(1);
}
}
/**
* Test PhysicsAdapter functionality
*/
async testPhysicsAdapter() {
console.log('\n📐 Testing PhysicsAdapter...');
// Test physics adapter instantiation
await this.runTest('PhysicsAdapter instantiation', async () => {
const adapter = new PhysicsAdapter();
this.assert(adapter instanceof PhysicsAdapter, 'PhysicsAdapter should be instantiated');
this.assert(adapter instanceof BaseAdapter, 'PhysicsAdapter should extend BaseAdapter');
this.assert(adapter.config.subject === 'física', 'Subject should be física');
this.assert(adapter.config.enhancedFeatures.includes('equations'), 'Should include equations feature');
});
// Test physics content generation
await this.runTest('Physics content generation', async () => {
const adapter = new PhysicsAdapter();
const analysis = await adapter.analyzeTopic('Movimento de projéteis e balística');
this.assert(analysis.subject === 'física', 'Should identify physics subject');
const content = await adapter.generateContent(analysis);
this.assert(content.metadata.subject === 'física', 'Content should be marked as physics');
this.assert(content.metadata.enhancedFeatures.includes('equations'), 'Should include enhanced features');
this.assert(content.components.equations, 'Should include equations component');
this.assert(content.components.diagrams, 'Should include diagrams component');
this.assert(content.components.calculations, 'Should include calculations component');
});
// Test physics-specific enhancements
await this.runTest('Physics enhanced features', async () => {
const adapter = new PhysicsAdapter();
const analysis = await adapter.analyzeTopic('Leis de Newton e dinâmica');
const content = await adapter.generateContent(analysis);
// Check equations component
this.assert(content.components.equations.type === 'equations', 'Equations component should exist');
this.assert(Array.isArray(content.components.equations.equations), 'Should have equations array');
// Check physics problem types
this.assert(content.metadata.physicsType, 'Should identify physics type');
// Check enhanced explanation
this.assert(
content.components.explanation.content.includes('Princípios Físicos'),
'Should include physics principles'
);
});
}
/**
* Test ChemistryAdapter functionality
*/
async testChemistryAdapter() {
console.log('\n🧪 Testing ChemistryAdapter...');
// Test chemistry adapter instantiation
await this.runTest('ChemistryAdapter instantiation', async () => {
const adapter = new ChemistryAdapter();
this.assert(adapter instanceof ChemistryAdapter, 'ChemistryAdapter should be instantiated');
this.assert(adapter instanceof BaseAdapter, 'ChemistryAdapter should extend BaseAdapter');
this.assert(adapter.config.subject === 'química', 'Subject should be química');
this.assert(adapter.config.enhancedFeatures.includes('molecular_structures'), 'Should include molecular structures');
});
// Test chemistry content generation
await this.runTest('Chemistry content generation', async () => {
const adapter = new ChemistryAdapter();
const analysis = await adapter.analyzeTopic('Ligações químicas e estrutura molecular');
this.assert(analysis.subject === 'química', 'Should identify chemistry subject');
const content = await adapter.generateContent(analysis);
this.assert(content.metadata.subject === 'química', 'Content should be marked as chemistry');
this.assert(content.metadata.enhancedFeatures.includes('reactions'), 'Should include enhanced features');
this.assert(content.components.molecular_structures, 'Should include molecular structures component');
this.assert(content.components.reactions, 'Should include reactions component');
this.assert(content.components.periodic_table, 'Should include periodic table component');
this.assert(content.components.laboratory, 'Should include laboratory component');
});
// Test chemistry-specific enhancements
await this.runTest('Chemistry enhanced features', async () => {
const adapter = new ChemistryAdapter();
const analysis = await adapter.analyzeTopic('Reações orgânicas e mecanismos');
const content = await adapter.generateContent(analysis);
// Check molecular structures component
this.assert(content.components.molecular_structures.type === 'molecular_structures', 'Molecular component should exist');
this.assert(content.components.molecular_structures.aspects, 'Should have molecular aspects');
// Check chemistry type identification
this.assert(content.metadata.chemistryType, 'Should identify chemistry type');
// Check enhanced explanation
this.assert(
content.components.explanation.content.includes('Princípios Químicos'),
'Should include chemistry principles'
);
});
}
/**
* Test HistoryAdapter functionality
*/
async testHistoryAdapter() {
console.log('\n📚 Testing HistoryAdapter...');
// Test history adapter instantiation
await this.runTest('HistoryAdapter instantiation', async () => {
const adapter = new HistoryAdapter();
this.assert(adapter instanceof HistoryAdapter, 'HistoryAdapter should be instantiated');
this.assert(adapter instanceof BaseAdapter, 'HistoryAdapter should extend BaseAdapter');
this.assert(adapter.config.subject === 'história', 'Subject should be história');
this.assert(adapter.config.enhancedFeatures.includes('timelines'), 'Should include timelines feature');
});
// Test history content generation
await this.runTest('History content generation', async () => {
const adapter = new HistoryAdapter();
const analysis = await adapter.analyzeTopic('Revolução Francesa e suas consequências');
this.assert(analysis.subject === 'história', 'Should identify history subject');
const content = await adapter.generateContent(analysis);
this.assert(content.metadata.subject === 'história', 'Content should be marked as history');
this.assert(content.metadata.enhancedFeatures.includes('causality'), 'Should include enhanced features');
this.assert(content.components.timeline, 'Should include timeline component');
this.assert(content.components.causality, 'Should include causality component');
this.assert(content.components.cultural_context, 'Should include cultural context component');
this.assert(content.components.primary_sources, 'Should include primary sources component');
});
// Test history-specific enhancements
await this.runTest('History enhanced features', async () => {
const adapter = new HistoryAdapter();
const analysis = await adapter.analyzeTopic('Segunda Guerra Mundial e impactos sociais');
const content = await adapter.generateContent(analysis);
// Check timeline component
this.assert(content.components.timeline.type === 'timeline', 'Timeline component should exist');
this.assert(Array.isArray(content.components.timeline.events), 'Should have timeline events');
// Check historical period identification
this.assert(content.metadata.historicalPeriod, 'Should identify historical period');
this.assert(content.metadata.historyType, 'Should identify history type');
// Check enhanced explanation
this.assert(
content.components.explanation.content.includes('Contexto Histórico'),
'Should include historical context'
);
});
}
/**
* Test AdapterFactory functionality
*/
async testAdapterFactory() {
console.log('\n🏭 Testing AdapterFactory...');
// Test adapter factory instantiation
await this.runTest('AdapterFactory instantiation', async () => {
const factory = new AdapterFactory();
this.assert(factory instanceof AdapterFactory, 'AdapterFactory should be instantiated');
this.assert(typeof factory.createAdapter === 'function', 'Should have createAdapter method');
this.assert(typeof factory.generateContentWithOptimalAdapter === 'function', 'Should have content generation method');
});
// Test available adapters
await this.runTest('Available adapters listing', async () => {
const factory = new AdapterFactory();
const adapters = factory.getAvailableAdapters();
this.assert(Array.isArray(adapters), 'Should return array of adapters');
this.assert(adapters.length >= 4, 'Should have at least 4 adapters (Base + 3 enhanced)');
const adapterNames = adapters.map(a => a.name);
this.assert(adapterNames.includes('BaseAdapter'), 'Should include BaseAdapter');
this.assert(adapterNames.includes('PhysicsAdapter'), 'Should include PhysicsAdapter');
this.assert(adapterNames.includes('ChemistryAdapter'), 'Should include ChemistryAdapter');
this.assert(adapterNames.includes('HistoryAdapter'), 'Should include HistoryAdapter');
});
// Test subject pattern matching
await this.runTest('Subject pattern matching', async () => {
const factory = new AdapterFactory();
// Test physics patterns
const physicsScore = factory.calculateSubjectScore(
'movimento projétil balística energia cinética',
factory.subjectPatterns.physics
);
this.assert(physicsScore > 0.5, 'Should detect physics patterns');
// Test chemistry patterns
const chemistryScore = factory.calculateSubjectScore(
'reação química ligações moleculares átomos',
factory.subjectPatterns.chemistry
);
this.assert(chemistryScore > 0.5, 'Should detect chemistry patterns');
// Test history patterns
const historyScore = factory.calculateSubjectScore(
'revolução francesa guerra independência',
factory.subjectPatterns.history
);
this.assert(historyScore > 0.5, 'Should detect history patterns');
});
}
/**
* Test adapter selection logic
*/
async testAdapterSelection() {
console.log('\n🎯 Testing Adapter Selection...');
// Test physics adapter selection
await this.runTest('Physics adapter selection', async () => {
const physicsAdapter = await createOptimalAdapter('Leis de Newton e movimento de projéteis');
this.assert(physicsAdapter instanceof PhysicsAdapter, 'Should select PhysicsAdapter for physics topics');
});
// Test chemistry adapter selection
await this.runTest('Chemistry adapter selection', async () => {
const chemistryAdapter = await createOptimalAdapter('Estrutura atômica e ligações químicas');
this.assert(chemistryAdapter instanceof ChemistryAdapter, 'Should select ChemistryAdapter for chemistry topics');
});
// Test history adapter selection
await this.runTest('History adapter selection', async () => {
const historyAdapter = await createOptimalAdapter('Revolução Industrial e transformações sociais');
this.assert(historyAdapter instanceof HistoryAdapter, 'Should select HistoryAdapter for history topics');
});
// Test fallback to BaseAdapter
await this.runTest('BaseAdapter fallback', async () => {
const baseAdapter = await createOptimalAdapter('Técnicas de jardinagem e cultivo de plantas');
this.assert(baseAdapter instanceof BaseAdapter, 'Should fallback to BaseAdapter for non-specialized topics');
this.assert(!(baseAdapter instanceof PhysicsAdapter), 'Should not be PhysicsAdapter');
this.assert(!(baseAdapter instanceof ChemistryAdapter), 'Should not be ChemistryAdapter');
this.assert(!(baseAdapter instanceof HistoryAdapter), 'Should not be HistoryAdapter');
});
// Test adapter validation
await this.runTest('Adapter selection validation', async () => {
const validation = await adapterFactory.validateAdapterSelection('Mecânica quântica e física moderna');
this.assert(validation.selectedAdapter, 'Should have selected adapter');
this.assert(validation.confidence >= 0, 'Should have confidence score');
this.assert(validation.analysis, 'Should have analysis result');
this.assert(validation.recommendation, 'Should have recommendation');
this.assert(Array.isArray(validation.alternatives), 'Should have alternatives array');
});
}
/**
* Test enhanced content generation
*/
async testEnhancedContentGeneration() {
console.log('\n✨ Testing Enhanced Content Generation...');
// Test physics enhanced content
await this.runTest('Physics enhanced content', async () => {
const content = await generateEnhancedContent('Balística e movimento de projéteis');
this.assert(content.metadata.adapterUsed === 'PhysicsAdapter', 'Should use PhysicsAdapter');
this.assert(Array.isArray(content.metadata.enhancedFeatures), 'Should have enhanced features');
this.assert(content.metadata.enhancedFeatures.includes('equations'), 'Should include equations');
this.assert(content.components.equations, 'Should have equations component');
});
// Test chemistry enhanced content
await this.runTest('Chemistry enhanced content', async () => {
const content = await generateEnhancedContent('Reações químicas e balanceamento');
this.assert(content.metadata.adapterUsed === 'ChemistryAdapter', 'Should use ChemistryAdapter');
this.assert(content.metadata.enhancedFeatures.includes('reactions'), 'Should include reactions');
this.assert(content.components.reactions, 'Should have reactions component');
});
// Test history enhanced content
await this.runTest('History enhanced content', async () => {
const content = await generateEnhancedContent('Idade Média e sistema feudal');
this.assert(content.metadata.adapterUsed === 'HistoryAdapter', 'Should use HistoryAdapter');
this.assert(content.metadata.enhancedFeatures.includes('timelines'), 'Should include timelines');
this.assert(content.components.timeline, 'Should have timeline component');
});
// Test universal content fallback
await this.runTest('Universal content fallback', async () => {
const content = await generateEnhancedContent('Técnicas de culinária e preparo de alimentos');
this.assert(content.metadata.adapterUsed === 'BaseAdapter', 'Should use BaseAdapter for universal topics');
this.assert(content.components.introduction, 'Should have basic components');
this.assert(content.components.explanation, 'Should have explanation');
this.assert(content.components.summary, 'Should have summary');
});
}
/**
* Test integration scenarios
*/
async testIntegrationScenarios() {
console.log('\n🔗 Testing Integration Scenarios...');
// Test mixed subject detection
await this.runTest('Mixed subject detection', async () => {
const content = await generateEnhancedContent('Física nuclear e aplicações na medicina');
// Should prioritize physics given stronger physics indicators
this.assert(content.metadata.adapterUsed === 'PhysicsAdapter', 'Should select primary subject adapter');
});
// Test English language fallback
await this.runTest('English language fallback', async () => {
const content = await generateEnhancedContent('Chemical bonds and molecular structure');
this.assert(content.metadata.adapterUsed === 'ChemistryAdapter', 'Should handle English chemistry topics');
});
// Test grade level adaptation in enhanced adapters
await this.runTest('Grade level adaptation', async () => {
const elementaryContent = await generateEnhancedContent(
'Força e movimento - 6º ano',
{ gradeLevel: 'fundamental-2' }
);
this.assert(elementaryContent.metadata.gradeLevel === 'fundamental-2', 'Should adapt to grade level');
const advancedContent = await generateEnhancedContent(
'Mecânica quântica - ensino superior',
{ gradeLevel: 'superior' }
);
this.assert(advancedContent.metadata.gradeLevel === 'superior', 'Should handle advanced levels');
});
}
/**
* Test performance metrics
*/
async testPerformanceMetrics() {
console.log('\n⚡ Testing Performance Metrics...');
// Test generation speed
await this.runTest('Enhanced adapter speed', async () => {
const startTime = Date.now();
const content = await generateEnhancedContent('Termodinâmica e transferência de calor');
const endTime = Date.now();
const generationTime = endTime - startTime;
this.assert(generationTime < 5000, `Generation should complete in <5s (took ${generationTime}ms)`);
this.assert(content.components, 'Should generate complete content structure');
});
// Test content quality
await this.runTest('Enhanced content quality', async () => {
const content = await generateEnhancedContent('Evolução das espécies e seleção natural');
// Check content completeness
this.assert(content.metadata, 'Should have metadata');
this.assert(content.components, 'Should have components');
this.assert(Object.keys(content.components).length >= 5, 'Should have multiple components');
// Check content substance
const explanation = content.components.explanation;
this.assert(explanation.content.length > 100, 'Should have substantial explanation content');
});
// Test memory usage (basic check)
await this.runTest('Memory efficiency', async () => {
const memBefore = process.memoryUsage().heapUsed;
// Generate multiple contents
for (let i = 0; i < 5; i++) {
await generateEnhancedContent(`Test topic ${i}`);
}
const memAfter = process.memoryUsage().heapUsed;
const memIncrease = memAfter - memBefore;
this.assert(memIncrease < 50 * 1024 * 1024, `Memory increase should be <50MB (was ${Math.round(memIncrease / 1024 / 1024)}MB)`);
});
}
/**
* Test fallback behavior
*/
async testFallbackBehavior() {
console.log('\n🛡️ Testing Fallback Behavior...');
// Test graceful degradation
await this.runTest('Graceful degradation', async () => {
// Test with malformed input
const content = await generateEnhancedContent('');
this.assert(content.metadata.adapterUsed === 'BaseAdapter', 'Should fallback for empty input');
this.assert(content.components, 'Should still generate content structure');
});
// Test error handling
await this.runTest('Error handling', async () => {
try {
// Test with extremely long input
const longInput = 'palavra '.repeat(1000);
const content = await generateEnhancedContent(longInput);
this.assert(content.components, 'Should handle long input gracefully');
} catch (error) {
this.assert(error.message.includes('generation failed'), 'Should provide meaningful error messages');
}
});
// Test adapter factory fallback
await this.runTest('Factory fallback mechanism', async () => {
const factory = new AdapterFactory();
// Mock an error scenario by creating invalid adapter analysis
const invalidAnalysis = {
subjectScores: {},
primarySubject: null,
confidence: 0,
specializationBenefit: 0,
recommendedAdapter: 'NonExistentAdapter',
fallbackRequired: true
};
const selectedAdapter = factory.selectOptimalAdapter(invalidAnalysis);
this.assert(selectedAdapter === 'BaseAdapter', 'Should fallback to BaseAdapter for invalid analysis');
});
}
/**
* Run individual test
*/
async runTest(testName, testFunction) {
this.totalTests++;
try {
const startTime = Date.now();
await testFunction();
const endTime = Date.now();
const duration = endTime - startTime;
this.passedTests++;
this.testResults.push({
name: testName,
status: 'PASS',
duration: duration,
error: null
});
console.log(` ✅ ${testName} (${duration}ms)`);
} catch (error) {
this.failedTests++;
this.testResults.push({
name: testName,
status: 'FAIL',
duration: 0,
error: error.message
});
console.log(` ❌ ${testName}: ${error.message}`);
}
}
/**
* Assert condition with message
*/
assert(condition, message) {
if (!condition) {
throw new Error(message || 'Assertion failed');
}
}
/**
* Print comprehensive test summary
*/
printTestSummary() {
const endTime = Date.now();
const totalDuration = endTime - this.startTime;
const successRate = ((this.passedTests / this.totalTests) * 100).toFixed(1);
console.log('\n' + '='.repeat(60));
console.log('📊 ENHANCED ADAPTERS TEST SUMMARY');
console.log('='.repeat(60));
console.log(`Total Tests: ${this.totalTests}`);
console.log(`Passed: ${this.passedTests}`);
console.log(`Failed: ${this.failedTests}`);
console.log(`Success Rate: ${successRate}%`);
console.log(`Total Duration: ${totalDuration}ms`);
if (this.failedTests > 0) {
console.log('\n❌ FAILED TESTS:');
this.testResults
.filter(result => result.status === 'FAIL')
.forEach(result => {
console.log(` • ${result.name}: ${result.error}`);
});
}
console.log('\n📈 PERFORMANCE METRICS:');
const avgDuration = this.testResults
.filter(r => r.status === 'PASS')
.reduce((sum, r) => sum + r.duration, 0) / this.passedTests;
console.log(`Average Test Duration: ${avgDuration.toFixed(1)}ms`);
const maxDuration = Math.max(...this.testResults.map(r => r.duration));
const slowestTest = this.testResults.find(r => r.duration === maxDuration);
console.log(`Slowest Test: ${slowestTest.name} (${maxDuration}ms)`);
console.log('\n🎯 ENHANCED FEATURES VALIDATED:');
console.log(' ✅ PhysicsAdapter: equations, calculations, diagrams');
console.log(' ✅ ChemistryAdapter: molecular structures, reactions, periodic table');
console.log(' ✅ HistoryAdapter: timelines, causality, cultural context');
console.log(' ✅ AdapterFactory: intelligent selection, fallback mechanism');
console.log(' ✅ Integration: seamless BaseAdapter compatibility');
if (this.passedTests === this.totalTests) {
console.log('\n🎉 ALL TESTS PASSED! Enhanced adapters are production-ready.');
process.exit(0);
} else {
console.log('\n⚠️ Some tests failed. Review failures before deployment.');
process.exit(1);
}
}
}
// Run tests if this file is executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
const testSuite = new EnhancedAdaptersTestSuite();
await testSuite.runAllTests();
}