import { describe, it, expect } from 'vitest';
import { op_not } from './not.js';
describe('NOT (0x19)', () => {
it('inverts all bits', () => {
const value = 0b11001100n;
const frame = createFrame({ stack: [value] });
expect(op_not(frame)).toBeNull();
const MAX = (1n << 256n) - 1n;
const expected = MAX - value; // ~a = MAX - a
expect(frame.stack[0]).toBe(expected);
});
it('converts zero to MAX', () => {
const frame = createFrame({ stack: [0n] });
expect(op_not(frame)).toBeNull();
const MAX = (1n << 256n) - 1n;
expect(frame.stack[0]).toBe(MAX);
});
it('converts MAX to zero', () => {
const MAX = (1n << 256n) - 1n;
const frame = createFrame({ stack: [MAX] });
expect(op_not(frame)).toBeNull();
expect(frame.stack[0]).toBe(0n);
});
it('is involutory (~~a = a)', () => {
const value = 0x123456789ABCDEFn;
const frame1 = createFrame({ stack: [value] });
op_not(frame1);
const frame2 = createFrame({ stack: [frame1.stack[0]] });
op_not(frame2);
expect(frame2.stack[0]).toBe(value);
});
it('inverts alternating pattern', () => {
const pattern = 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAn;
const expected = 0x5555555555555555555555555555555555555555555555555555555555555555n;
const frame = createFrame({ stack: [pattern] });
expect(op_not(frame)).toBeNull();
expect(frame.stack[0]).toBe(expected);
});
it('prepares two\'s complement', () => {
const value = 5n;
const frame = createFrame({ stack: [value] });
expect(op_not(frame)).toBeNull();
const onesComplement = frame.stack[0];
const twosComplement = (onesComplement + 1n) & ((1n << 256n) - 1n);
// Two's complement of 5 should be -5 (MAX_UINT256 - 4)
const MAX = (1n << 256n) - 1n;
expect(twosComplement).toBe(MAX - 4n);
});
it('returns StackUnderflow with empty stack', () => {
const frame = createFrame({ stack: [] });
expect(op_not(frame)).toEqual({ type: 'StackUnderflow' });
});
it('returns OutOfGas when insufficient gas', () => {
const frame = createFrame({ stack: [0x123n], gasRemaining: 2n });
expect(op_not(frame)).toEqual({ type: 'OutOfGas' });
});
});