import { describe, it, expect } from 'vitest';
import { op_xor } from './xor.js';
describe('XOR (0x18)', () => {
it('performs basic XOR', () => {
const frame = createFrame({ stack: [0b1100n, 0b1010n] });
expect(op_xor(frame)).toBeNull();
expect(frame.stack[0]).toBe(0b0110n);
});
it('toggles bits', () => {
const value = 0b0000n;
const toggle = 0b0101n;
const frame = createFrame({ stack: [value, toggle] });
expect(op_xor(frame)).toBeNull();
expect(frame.stack[0]).toBe(0b0101n);
});
it('handles identity (XOR with zero)', () => {
const value = 0x123456n;
const frame = createFrame({ stack: [value, 0n] });
expect(op_xor(frame)).toBeNull();
expect(frame.stack[0]).toBe(value);
});
it('is self-inverse (a ^ a = 0)', () => {
const value = 0x123456n;
const frame = createFrame({ stack: [value, value] });
expect(op_xor(frame)).toBeNull();
expect(frame.stack[0]).toBe(0n);
});
it('has involution property ((a ^ b) ^ b = a)', () => {
const a = 0x123456n;
const b = 0xABCDEFn;
const frame1 = createFrame({ stack: [a, b] });
op_xor(frame1);
const intermediate = frame1.stack[0];
const frame2 = createFrame({ stack: [intermediate, b] });
op_xor(frame2);
expect(frame2.stack[0]).toBe(a);
});
it('acts as NOT when XOR with MAX', () => {
const MAX = (1n << 256n) - 1n;
const value = 0xAAAAn;
const frame = createFrame({ stack: [value, MAX] });
op_xor(frame);
expect(frame.stack[0]).toBe(~value & MAX);
});
it('is commutative', () => {
const a = 0xAAAAn;
const b = 0x5555n;
const frame1 = createFrame({ stack: [a, b] });
const frame2 = createFrame({ stack: [b, a] });
op_xor(frame1);
op_xor(frame2);
expect(frame1.stack[0]).toBe(frame2.stack[0]);
});
it('returns StackUnderflow with insufficient stack', () => {
const frame = createFrame({ stack: [0x123n] });
expect(op_xor(frame)).toEqual({ type: 'StackUnderflow' });
});
it('returns OutOfGas when insufficient gas', () => {
const frame = createFrame({ stack: [0x123n, 0x456n], gasRemaining: 2n });
expect(op_xor(frame)).toEqual({ type: 'OutOfGas' });
});
});