const ForthInterpreter = require('./forth.js'); console.log('๐Ÿงช Comprehensive Cross-Stack Operations Test Suite\n'); let state = ForthInterpreter.createInitialState(); let testCount = 0; let passCount = 0; // Test helper function const test = (name, testFn) => { testCount++; try { testFn(); console.log(`โœ… ${name}`); passCount++; } catch (error) { console.log(`โŒ ${name}: ${error.message}`); } }; // Test 1: Basic Cross-Stack Operations test('dup.stacks - Basic Functionality', () => { state = ForthInterpreter.createInitialState(); // Set up source stack state = ForthInterpreter.parseAndExecute(state, 'focus.red'); state = ForthInterpreter.parseAndExecute(state, '42'); // Execute dup.stacks state = ForthInterpreter.parseAndExecute(state, 'dup.stacks'); if (!state.crossStackInProgress) throw new Error('Should set cross-stack mode'); if (state.crossStackOperation !== 'dup') throw new Error('Should set operation to dup'); // Specify target stack state = ForthInterpreter.parseAndExecute(state, '2'); // Target Teal stack if (state.crossStackInProgress) throw new Error('Should clear cross-stack mode'); // Verify results if (state.stacks[0].length !== 1) throw new Error('Source stack should still have 1 item'); if (state.stacks[1].length !== 1) throw new Error('Target stack should have 1 item'); if (state.stacks[0][state.stacks[0].length - 1] !== 42) throw new Error('Source stack should still have 42'); if (state.stacks[1][state.stacks[1].length - 1] !== 42) throw new Error('Target stack should have 42'); }); test('over.stacks - Copy Second Item', () => { state = ForthInterpreter.createInitialState(); // Set up source stack with multiple items state = ForthInterpreter.parseAndExecute(state, 'focus.blue'); state = ForthInterpreter.parseAndExecute(state, '10'); state = ForthInterpreter.parseAndExecute(state, '20'); state = ForthInterpreter.parseAndExecute(state, '30'); // Execute over.stacks state = ForthInterpreter.parseAndExecute(state, 'over.stacks'); if (!state.crossStackInProgress) throw new Error('Should set cross-stack mode'); // Specify target stack state = ForthInterpreter.parseAndExecute(state, '1'); // Target Red stack if (state.crossStackInProgress) throw new Error('Should clear cross-stack mode'); // Verify results if (state.stacks[2].length !== 3) throw new Error('Source stack should still have 3 items'); if (state.stacks[0].length !== 1) throw new Error('Target stack should have 1 item'); if (state.stacks[0][state.stacks[0].length - 1] !== 20) throw new Error('Target stack should have second item (20)'); }); test('swap.stacks - Swap Top Items', () => { state = ForthInterpreter.createInitialState(); // Set up source stack state = ForthInterpreter.parseAndExecute(state, 'focus.yellow'); state = ForthInterpreter.parseAndExecute(state, '100'); state = ForthInterpreter.parseAndExecute(state, '200'); // Execute swap.stacks state = ForthInterpreter.parseAndExecute(state, 'swap.stacks'); if (!state.crossStackInProgress) throw new Error('Should set cross-stack mode'); // Specify target stack state = ForthInterpreter.parseAndExecute(state, '3'); // Target Blue stack if (state.crossStackInProgress) throw new Error('Should clear cross-stack mode'); // Verify results if (state.stacks[3].length !== 2) throw new Error('Source stack should still have 2 items'); if (state.stacks[2].length !== 2) throw new Error('Target stack should have 2 items'); if (state.stacks[3][state.stacks[3].length - 1] !== 200) throw new Error('Source stack top should be 200'); if (state.stacks[3][state.stacks[3].length - 2] !== 100) throw new Error('Source stack second should be 100'); if (state.stacks[2][state.stacks[2].length - 1] !== 100) throw new Error('Target stack top should be 100'); if (state.stacks[2][state.stacks[2].length - 2] !== 200) throw new Error('Target stack second should be 200'); }); test('nip.stacks - Move Second Item', () => { state = ForthInterpreter.createInitialState(); // Set up source stack state = ForthInterpreter.parseAndExecute(state, 'focus.teal'); state = ForthInterpreter.parseAndExecute(state, '50'); state = ForthInterpreter.parseAndExecute(state, '60'); // Execute nip.stacks state = ForthInterpreter.parseAndExecute(state, 'nip.stacks'); if (!state.crossStackInProgress) throw new Error('Should set cross-stack mode'); // Specify target stack state = ForthInterpreter.parseAndExecute(state, '4'); // Target Yellow stack if (state.crossStackInProgress) throw new Error('Should clear cross-stack mode'); // Verify results if (state.stacks[1].length !== 1) throw new Error('Source stack should have 1 item after nip'); if (state.stacks[3].length !== 1) throw new Error('Target stack should have 1 item'); if (state.stacks[1][state.stacks[1].length - 1] !== 60) throw new Error('Source stack should keep top item (60)'); if (state.stacks[3][state.stacks[3].length - 1] !== 50) throw new Error('Target stack should have second item (50)'); }); test('tuck.stacks - Tuck Operation', () => { state = ForthInterpreter.createInitialState(); // Set up source stack state = ForthInterpreter.parseAndExecute(state, 'focus.red'); state = ForthInterpreter.parseAndExecute(state, '7'); state = ForthInterpreter.parseAndExecute(state, '8'); // Execute tuck.stacks state = ForthInterpreter.parseAndExecute(state, 'tuck.stacks'); if (!state.crossStackInProgress) throw new Error('Should set cross-stack mode'); // Specify target stack state = ForthInterpreter.parseAndExecute(state, '2'); // Target Teal stack if (state.crossStackInProgress) throw new Error('Should clear cross-stack mode'); // Verify results if (state.stacks[0].length !== 1) throw new Error('Source stack should have 1 item after tuck'); if (state.stacks[1].length !== 3) throw new Error('Target stack should have 3 items'); if (state.stacks[0][state.stacks[0].length - 1] !== 7) throw new Error('Source stack should keep top item (7)'); if (state.stacks[1][state.stacks[1].length - 1] !== 8) throw new Error('Target stack should have 8 at top'); if (state.stacks[1][state.stacks[1].length - 2] !== 7) throw new Error('Target stack should have 7 in middle'); if (state.stacks[1][state.stacks[1].length - 3] !== 8) throw new Error('Target stack should have 8 at bottom'); }); test('rot.stacks - Rotate Top 3 Items', () => { state = ForthInterpreter.createInitialState(); // Set up source stack state = ForthInterpreter.parseAndExecute(state, 'focus.blue'); state = ForthInterpreter.parseAndExecute(state, '1'); state = ForthInterpreter.parseAndExecute(state, '2'); state = ForthInterpreter.parseAndExecute(state, '3'); // Execute rot.stacks state = ForthInterpreter.parseAndExecute(state, 'rot.stacks'); if (!state.crossStackInProgress) throw new Error('Should set cross-stack mode'); // Specify target stack state = ForthInterpreter.parseAndExecute(state, '1'); // Target Red stack if (state.crossStackInProgress) throw new Error('Should clear cross-stack mode'); // Verify results if (state.stacks[2].length !== 3) throw new Error('Source stack should still have 3 items'); if (state.stacks[0].length !== 3) throw new Error('Target stack should have 3 items'); // Source stack should be rotated: [1, 3, 2] (top=2, second=3, third=1) if (state.stacks[2][state.stacks[2].length - 1] !== 2) throw new Error('Source stack top should be 2'); if (state.stacks[2][state.stacks[2].length - 2] !== 3) throw new Error('Source stack second should be 3'); if (state.stacks[2][state.stacks[2].length - 3] !== 1) throw new Error('Source stack third should be 1'); // Target stack should have rotated items: [1, 3, 2] (top=2, second=3, third=1) if (state.stacks[0][state.stacks[0].length - 1] !== 2) throw new Error('Target stack top should be 2'); if (state.stacks[0][state.stacks[0].length - 2] !== 3) throw new Error('Target stack second should be 3'); if (state.stacks[0][state.stacks[0].length - 3] !== 1) throw new Error('Target stack third should be 1'); }); test('2dup.stacks - Duplicate Top 2 Items', () => { state = ForthInterpreter.createInitialState(); // Set up source stack state = ForthInterpreter.parseAndExecute(state, 'focus.yellow'); state = ForthInterpreter.parseAndExecute(state, '25'); state = ForthInterpreter.parseAndExecute(state, '35'); // Execute 2dup.stacks state = ForthInterpreter.parseAndExecute(state, '2dup.stacks'); if (!state.crossStackInProgress) throw new Error('Should set cross-stack mode'); // Specify target stack state = ForthInterpreter.parseAndExecute(state, '3'); // Target Blue stack if (state.crossStackInProgress) throw new Error('Should clear cross-stack mode'); // Verify results if (state.stacks[3].length !== 2) throw new Error('Source stack should still have 2 items'); if (state.stacks[2].length !== 2) throw new Error('Target stack should have 2 items'); if (state.stacks[3][state.stacks[3].length - 1] !== 35) throw new Error('Source stack top should be 35'); if (state.stacks[3][state.stacks[3].length - 2] !== 25) throw new Error('Source stack second should be 25'); if (state.stacks[2][state.stacks[2].length - 1] !== 35) throw new Error('Target stack top should be 35'); if (state.stacks[2][state.stacks[2].length - 2] !== 25) throw new Error('Target stack second should be 25'); }); test('2over.stacks - Copy Second Pair', () => { state = ForthInterpreter.createInitialState(); // Set up source stack with 4 items state = ForthInterpreter.parseAndExecute(state, 'focus.red'); state = ForthInterpreter.parseAndExecute(state, '10'); state = ForthInterpreter.parseAndExecute(state, '20'); state = ForthInterpreter.parseAndExecute(state, '30'); state = ForthInterpreter.parseAndExecute(state, '40'); // Execute 2over.stacks state = ForthInterpreter.parseAndExecute(state, '2over.stacks'); if (!state.crossStackInProgress) throw new Error('Should set cross-stack mode'); // Specify target stack state = ForthInterpreter.parseAndExecute(state, '2'); // Target Teal stack if (state.crossStackInProgress) throw new Error('Should clear cross-stack mode'); // Verify results if (state.stacks[0].length !== 4) throw new Error('Source stack should still have 4 items'); if (state.stacks[1].length !== 2) throw new Error('Target stack should have 2 items'); if (state.stacks[1][state.stacks[1].length - 1] !== 20) throw new Error('Target stack top should be 20'); if (state.stacks[1][state.stacks[1].length - 2] !== 30) throw new Error('Target stack second should be 30'); }); test('2swap.stacks - Swap Top 2 Pairs', () => { state = ForthInterpreter.createInitialState(); // Set up source stack with 4 items state = ForthInterpreter.parseAndExecute(state, 'focus.teal'); state = ForthInterpreter.parseAndExecute(state, '1'); state = ForthInterpreter.parseAndExecute(state, '2'); state = ForthInterpreter.parseAndExecute(state, '3'); state = ForthInterpreter.parseAndExecute(state, '4'); // Execute 2swap.stacks state = ForthInterpreter.parseAndExecute(state, '2swap.stacks'); if (!state.crossStackInProgress) throw new Error('Should set cross-stack mode'); // Specify target stack state = ForthInterpreter.parseAndExecute(state, '1'); // Target Red stack if (state.crossStackInProgress) throw new Error('Should clear cross-stack mode'); // Verify results if (state.stacks[1].length !== 4) throw new Error('Source stack should still have 4 items'); if (state.stacks[0].length !== 4) throw new Error('Target stack should have 4 items'); // Source stack should be: [1, 2, 3, 4] (top=4, second=3, third=2, fourth=1) if (state.stacks[1][state.stacks[1].length - 1] !== 4) throw new Error('Source stack top should be 4'); if (state.stacks[1][state.stacks[1].length - 2] !== 3) throw new Error('Source stack second should be 3'); if (state.stacks[1][state.stacks[1].length - 3] !== 2) throw new Error('Source stack third should be 2'); if (state.stacks[1][state.stacks[1].length - 4] !== 1) throw new Error('Source stack fourth should be 1'); // Target stack should be: [1, 2, 3, 4] (top=4, second=3, third=2, fourth=1) if (state.stacks[0][state.stacks[0].length - 1] !== 4) throw new Error('Target stack top should be 4'); if (state.stacks[0][state.stacks[0].length - 2] !== 3) throw new Error('Target stack second should be 3'); if (state.stacks[0][state.stacks[0].length - 3] !== 2) throw new Error('Target stack third should be 2'); if (state.stacks[0][state.stacks[0].length - 4] !== 1) throw new Error('Target stack fourth should be 1'); }); // Test 2: Error Handling test('Error Handling - Stack Underflow', () => { state = ForthInterpreter.createInitialState(); // Try dup.stacks on empty stack state = ForthInterpreter.parseAndExecute(state, 'focus.red'); state = ForthInterpreter.parseAndExecute(state, 'dup.stacks'); const lastOutput = state.output[state.output.length - 1]; if (!lastOutput.includes('Error: Stack underflow')) { throw new Error('Should show stack underflow error'); } }); test('Error Handling - Invalid Target Stack', () => { state = ForthInterpreter.createInitialState(); // Set up valid operation state = ForthInterpreter.parseAndExecute(state, 'focus.red'); state = ForthInterpreter.parseAndExecute(state, '42'); state = ForthInterpreter.parseAndExecute(state, 'dup.stacks'); // Try invalid target stack state = ForthInterpreter.parseAndExecute(state, '5'); // Invalid stack number const lastOutput = state.output[state.output.length - 1]; if (!lastOutput.includes('Error: Invalid target stack')) { throw new Error('Should show invalid target stack error'); } if (state.crossStackInProgress) { throw new Error('Should clear cross-stack mode on error'); } }); // Test 3: Edge Cases test('Edge Cases - Single Item Operations', () => { state = ForthInterpreter.createInitialState(); // Test over.stacks with only 1 item state = ForthInterpreter.parseAndExecute(state, 'focus.blue'); state = ForthInterpreter.parseAndExecute(state, '100'); state = ForthInterpreter.parseAndExecute(state, 'over.stacks'); const lastOutput = state.output[state.output.length - 1]; if (!lastOutput.includes('Error: Stack underflow')) { throw new Error('Should show stack underflow error for over.stacks with 1 item'); } }); test('Edge Cases - Focus Persistence', () => { state = ForthInterpreter.createInitialState(); // Set focus and perform operation state = ForthInterpreter.parseAndExecute(state, 'focus.yellow'); const originalFocus = state.focusedStack; state = ForthInterpreter.parseAndExecute(state, '50'); state = ForthInterpreter.parseAndExecute(state, 'dup.stacks'); state = ForthInterpreter.parseAndExecute(state, '1'); if (state.focusedStack !== originalFocus) { throw new Error('Focus should persist through cross-stack operations'); } }); // Test 4: Complex Workflows test('Complex Workflows - Multi-Operation Chain', () => { state = ForthInterpreter.createInitialState(); // Set up multiple stacks state = ForthInterpreter.parseAndExecute(state, 'focus.red'); state = ForthInterpreter.parseAndExecute(state, '100'); state = ForthInterpreter.parseAndExecute(state, '200'); state = ForthInterpreter.parseAndExecute(state, 'focus.teal'); state = ForthInterpreter.parseAndExecute(state, '300'); // Chain operations state = ForthInterpreter.parseAndExecute(state, 'dup.stacks'); state = ForthInterpreter.parseAndExecute(state, '1'); // Target Red state = ForthInterpreter.parseAndExecute(state, 'focus.red'); state = ForthInterpreter.parseAndExecute(state, 'over.stacks'); state = ForthInterpreter.parseAndExecute(state, '3'); // Target Blue // Verify final state if (state.stacks[0].length !== 3) throw new Error('Red stack should have 3 items'); if (state.stacks[1].length !== 1) throw new Error('Teal stack should have 1 item'); if (state.stacks[2].length !== 1) throw new Error('Blue stack should have 1 item'); }); // Test 5: State Management test('State Management - Cross-Stack Mode Reset', () => { state = ForthInterpreter.createInitialState(); // Start operation state = ForthInterpreter.parseAndExecute(state, 'focus.red'); state = ForthInterpreter.parseAndExecute(state, '42'); state = ForthInterpreter.parseAndExecute(state, 'dup.stacks'); if (!state.crossStackInProgress) throw new Error('Should set cross-stack mode'); // Complete operation state = ForthInterpreter.parseAndExecute(state, '2'); if (state.crossStackInProgress) throw new Error('Should clear cross-stack mode'); if (state.crossStackOperation !== null) throw new Error('Should clear operation'); if (state.crossStackData !== null) throw new Error('Should clear data'); }); console.log(`\n๐Ÿ“Š Test Results: ${passCount}/${testCount} tests passed`); console.log(`๐ŸŽฏ Success Rate: ${((passCount / testCount) * 100).toFixed(1)}%`); if (passCount === testCount) { console.log('\n๐ŸŽ‰ All cross-stack operation tests passed!'); } else { console.log('\nโš ๏ธ Some tests failed. Please review the implementation.'); } console.log('\n๐Ÿš€ Cross-stack operations test suite complete!');