Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
8.7 kB ยท 253 lines
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254// Test the instance manager for hierarchy and recursion detection// Validates our recursion detection and cycle prevention strategies
import { KidLispInstanceManager } from './instance-manager-prototype.mjs';import { KidLispCacheManager } from './cache-manager-prototype.mjs';import { mockStore } from './mock-network.mjs';
async function testInstanceManager() { console.log('๐๏ธ Testing KidLisp Instance Manager\n'); const cacheManager = new KidLispCacheManager(); const instanceManager = new KidLispInstanceManager(cacheManager); let testsPassed = 0; let totalTests = 0; function assert(condition, message) { totalTests++; if (condition) { console.log(`โ
${message}`); testsPassed++; } else { console.log(`โ ${message}`); } } // Test 1: Basic instance creation and hierarchy console.log('๐ณ Test 1: Instance Hierarchy'); instanceManager.clearAllInstances(); const rootInstance = instanceManager.createInstance({ type: 'main-piece', bounds: { x: 0, y: 0, width: 400, height: 400 }, cacheId: 'cow' }); assert(rootInstance.id !== null, 'Created root instance'); assert(rootInstance.depth === 0, 'Root instance has depth 0'); assert(rootInstance.parentId === null, 'Root instance has no parent'); const childInstance = instanceManager.createInstance({ parentId: rootInstance.id, type: 'embedded-layer', bounds: { x: 10, y: 10, width: 100, height: 100 }, cacheId: '39i' }); assert(childInstance.parentId === rootInstance.id, 'Child instance has correct parent'); assert(childInstance.depth === 1, 'Child instance has depth 1'); assert(rootInstance.children.has(childInstance.id), 'Parent tracks child instance'); // Test 2: Recursion depth tracking console.log('\n๐ Test 2: Recursion Depth Tracking'); let currentParent = childInstance; for (let i = 2; i <= 5; i++) { const deepInstance = instanceManager.createInstance({ parentId: currentParent.id, type: 'embedded-layer', bounds: { x: i * 10, y: i * 10, width: 80, height: 80 }, cacheId: `deep-${i}` }); assert(deepInstance.depth === i, `Deep instance ${i} has correct depth ${i}`); currentParent = deepInstance; } const stats = instanceManager.getStats(); assert(stats.maxDepthReached === 5, `Max depth tracked correctly (${stats.maxDepthReached})`); // Test 3: Simple cycle detection console.log('\n๐ Test 3: Simple Cycle Detection'); instanceManager.clearAllInstances(); const cycleRoot = instanceManager.createInstance({ type: 'main-piece', cacheId: 'recursive-a' }); // Execute recursive-a which references recursive-b (should work normally) const result1 = await instanceManager.executeWithRecursionGuard( cycleRoot.id, '(paint ($recursive-b 0 0 100 100))', {} ); // This should work since it's A -> B (no cycle yet) assert(result1.type === 'execution-result' || result1.type === 'cycle-error', 'First execution completed'); const embeddedCount = result1.embeddedCount || 0; assert(embeddedCount >= 0, `Created ${embeddedCount} embedded instances`); // Check if cycle would be detected on deeper recursion const wouldCycle = instanceManager.wouldCreateCycle('recursive-a'); assert(wouldCycle === false, 'Not in cycle yet (only 1 level deep)'); // Test 4: Actual cycle detection console.log('\n๐ Test 4: Cycle Detection'); instanceManager.clearAllInstances(); const cycleTestRoot = instanceManager.createInstance({ type: 'main-piece', cacheId: 'recursive-a' }); // Start execution that will create A -> B -> A cycle instanceManager.recursionStack = ['recursive-a']; // Simulate being in execution of A const cycleResult = await instanceManager.executeWithRecursionGuard( cycleTestRoot.id, '(paint ($recursive-a 0 0 50 50))', // A trying to call A again {} ); assert(cycleResult.type === 'cycle-error', 'Detected cycle error'); assert(cycleResult.cycle.includes('recursive-a'), 'Cycle path includes recursive-a'); const cycleStats = instanceManager.getStats(); assert(cycleStats.cyclesDetected > 0, 'Cycle detection counter incremented'); // Test 5: Maximum depth prevention console.log('\nโฌ๏ธ Test 5: Maximum Depth Prevention'); instanceManager.clearAllInstances(); instanceManager.maxRecursionDepth = 3; // Set low limit for testing let deepParent = instanceManager.createInstance({ type: 'main-piece', cacheId: 'deep-1' }); // Create instances at increasing depths for (let i = 2; i <= 5; i++) { deepParent = instanceManager.createInstance({ parentId: deepParent.id, type: 'embedded-layer', cacheId: `deep-${i}` }); } // Try to execute at depth 4 (should fail with maxDepth = 3) const depthResult = await instanceManager.executeWithRecursionGuard( deepParent.id, '(paint (circle 10 10 5))', {} ); assert(depthResult.type === 'depth-error', 'Detected depth limit error'); assert(depthResult.depth >= instanceManager.maxRecursionDepth, 'Error at correct depth'); const depthStats = instanceManager.getStats(); assert(depthStats.recursionDetected > 0, 'Recursion detection counter incremented'); // Test 6: Hierarchy tree structure console.log('\n๐ฒ Test 6: Hierarchy Tree Structure'); instanceManager.clearAllInstances(); instanceManager.maxRecursionDepth = 10; // Reset to normal const treeRoot = instanceManager.createInstance({ type: 'main-piece', cacheId: 'cow' }); const child1 = instanceManager.createInstance({ parentId: treeRoot.id, type: 'embedded-layer', cacheId: '39i' }); const child2 = instanceManager.createInstance({ parentId: treeRoot.id, type: 'embedded-layer', cacheId: 'r2f' }); const grandchild = instanceManager.createInstance({ parentId: child1.id, type: 'embedded-layer', cacheId: 'deep-1' }); const tree = instanceManager.getHierarchyTree(treeRoot.id); assert(tree.id === treeRoot.id, 'Tree root matches created root'); assert(tree.children.length === 2, 'Root has 2 children'); assert(tree.children[0].children.length === 1, 'First child has 1 grandchild'); assert(tree.children[1].children.length === 0, 'Second child has no children'); // Test 7: Garbage collection console.log('\n๐๏ธ Test 7: Garbage Collection'); const beforeGC = instanceManager.getStats(); // Simulate old instances (make them appear old) for (const instance of instanceManager.instances.values()) { instance.lastUsed = Date.now() - 70000; // 70 seconds ago } const gcCount = instanceManager.garbageCollect(60000); // 60 second threshold const afterGC = instanceManager.getStats(); assert(gcCount > 0, `Garbage collected ${gcCount} instances`); assert(afterGC.totalInstances < beforeGC.totalInstances, 'Instance count decreased'); assert(afterGC.instancesGarbageCollected > 0, 'GC counter incremented'); // Test 8: Real execution simulation console.log('\n๐ฏ Test 8: Real Execution Simulation'); instanceManager.clearAllInstances(); const execRoot = instanceManager.createInstance({ type: 'main-piece', cacheId: 'cow' }); const execResult = await instanceManager.executeWithRecursionGuard( execRoot.id, '(paint ($39i 10 10 100 100) ($r2f 120 10 100 100))', {} ); assert(execResult.type === 'execution-result', 'Execution completed successfully'); assert(execResult.embeddedCount === 2, 'Created 2 embedded instances'); assert(execResult.embeddedResults.length === 2, 'Got results from both embedded instances'); // Check that child instances were created const finalStats = instanceManager.getStats(); assert(finalStats.totalInstances >= 3, 'Created root + 2 child instances'); console.log(' ๐ Final execution stats:', { totalInstances: finalStats.totalInstances, maxDepth: finalStats.maxDepthReached, cyclesDetected: finalStats.cyclesDetected, recursionDetected: finalStats.recursionDetected }); // Summary console.log('\n๐ Test Summary'); console.log(`โ
Passed: ${testsPassed}/${totalTests} tests`); if (testsPassed === totalTests) { console.log('๐ All instance manager tests passed!'); return true; } else { console.log('โ Some tests failed'); return false; }}
// Run tests if called directlyif (import.meta.url === `file://${process.argv[1]}`) { testInstanceManager().then(success => { process.exit(success ? 0 : 1); });}
export { testInstanceManager };