@@ -1429,3 +1429,53 @@ func TestVM_OpJump_NegativeOffset(t *testing.T) {
14291429 require .Error (t , err )
14301430 require .Contains (t , err .Error (), "negative jump offset is invalid" )
14311431}
1432+
1433+ func TestVM_StackUnderflow (t * testing.T ) {
1434+ tests := []struct {
1435+ name string
1436+ bytecode []vm.Opcode
1437+ args []int
1438+ expectError string
1439+ }{
1440+ {
1441+ name : "pop after push" ,
1442+ bytecode : []vm.Opcode {vm .OpInt , vm .OpPop },
1443+ args : []int {42 , 0 },
1444+ },
1445+ {
1446+ name : "underflow after valid operations" ,
1447+ bytecode : []vm.Opcode {vm .OpInt , vm .OpInt , vm .OpPop , vm .OpPop , vm .OpPop },
1448+ args : []int {1 , 2 , 0 , 0 , 0 },
1449+ expectError : "stack underflow" ,
1450+ },
1451+ {
1452+ name : "pop on empty stack" ,
1453+ bytecode : []vm.Opcode {vm .OpPop },
1454+ args : []int {0 },
1455+ expectError : "stack underflow" ,
1456+ },
1457+ {
1458+ name : "pop after push" ,
1459+ bytecode : []vm.Opcode {vm .OpInt , vm .OpPop },
1460+ args : []int {123 , 0 },
1461+ },
1462+ }
1463+
1464+ for _ , tt := range tests {
1465+ t .Run (tt .name , func (t * testing.T ) {
1466+ program := & vm.Program {
1467+ Bytecode : tt .bytecode ,
1468+ Arguments : tt .args ,
1469+ Constants : []any {},
1470+ }
1471+
1472+ _ , err := vm .Run (program , nil )
1473+ if tt .expectError != "" {
1474+ require .Error (t , err )
1475+ require .Contains (t , err .Error (), tt .expectError )
1476+ } else {
1477+ require .NoError (t , err )
1478+ }
1479+ })
1480+ }
1481+ }
0 commit comments