ReefVM/tests/bitwise.test.ts

108 lines
3.3 KiB
TypeScript

import { expect, describe, test } from 'bun:test'
import { toBytecode, run } from '#reef'
describe('bitwise operations', () => {
test('BIT_AND', async () => {
const bytecode = toBytecode([
["PUSH", 5], ["PUSH", 3], ["BIT_AND"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 1 })
})
test('BIT_AND with zero', async () => {
const bytecode = toBytecode([
["PUSH", 5], ["PUSH", 0], ["BIT_AND"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 0 })
})
test('BIT_OR', async () => {
const bytecode = toBytecode([
["PUSH", 5], ["PUSH", 3], ["BIT_OR"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 7 })
})
test('BIT_OR with zero', async () => {
const bytecode = toBytecode([
["PUSH", 5], ["PUSH", 0], ["BIT_OR"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 5 })
})
test('BIT_XOR', async () => {
const bytecode = toBytecode([
["PUSH", 5], ["PUSH", 3], ["BIT_XOR"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 6 })
})
test('BIT_XOR with itself returns zero', async () => {
const bytecode = toBytecode([
["PUSH", 5], ["PUSH", 5], ["BIT_XOR"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 0 })
})
test('BIT_SHL', async () => {
const bytecode = toBytecode([
["PUSH", 5], ["PUSH", 2], ["BIT_SHL"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 20 })
})
test('BIT_SHL by zero', async () => {
const bytecode = toBytecode([
["PUSH", 5], ["PUSH", 0], ["BIT_SHL"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 5 })
})
test('BIT_SHR', async () => {
const bytecode = toBytecode([
["PUSH", 20], ["PUSH", 2], ["BIT_SHR"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 5 })
})
test('BIT_SHR preserves sign for negative numbers', async () => {
const bytecode = toBytecode([
["PUSH", -20], ["PUSH", 2], ["BIT_SHR"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: -5 })
})
test('BIT_USHR', async () => {
const bytecode = toBytecode([
["PUSH", -1], ["PUSH", 1], ["BIT_USHR"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 2147483647 })
})
test('BIT_USHR does not preserve sign', async () => {
const bytecode = toBytecode([
["PUSH", -8], ["PUSH", 1], ["BIT_USHR"], ["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 2147483644 })
})
test('compound bitwise operations', async () => {
const bytecode = toBytecode([
// (5 & 3) | (8 ^ 12)
["PUSH", 5], ["PUSH", 3], ["BIT_AND"], // stack: [1]
["PUSH", 8], ["PUSH", 12], ["BIT_XOR"], // stack: [1, 4]
["BIT_OR"], // stack: [5]
["HALT"]
])
expect(await run(bytecode)).toEqual({ type: 'number', value: 5 })
})
test('shift with large shift amounts', async () => {
const bytecode = toBytecode([
["PUSH", 1], ["PUSH", 31], ["BIT_SHL"], ["HALT"]
])
// 1 << 31 = -2147483648 (most significant bit set)
expect(await run(bytecode)).toEqual({ type: 'number', value: -2147483648 })
})
})