about summary refs log tree commit diff stats
path: root/forth/foreforthfourth/test-cross-stack-complete.js
diff options
context:
space:
mode:
Diffstat (limited to 'forth/foreforthfourth/test-cross-stack-complete.js')
-rw-r--r--forth/foreforthfourth/test-cross-stack-complete.js373
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!');