diff options
Diffstat (limited to 'forth/foreforthfourth/test-cross-stack-complete.js')
-rw-r--r-- | forth/foreforthfourth/test-cross-stack-complete.js | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/forth/foreforthfourth/test-cross-stack-complete.js b/forth/foreforthfourth/test-cross-stack-complete.js new file mode 100644 index 0000000..22f7a16 --- /dev/null +++ b/forth/foreforthfourth/test-cross-stack-complete.js @@ -0,0 +1,373 @@ +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!'); |