import { describe, it, expect } from 'vitest';
import { shl } from './shl.js';
describe('SHL (0x1b)', () => {
it('shifts left by 8 bits', () => {
const frame = createFrame({ stack: [8n, 0xFFn] });
expect(shl(frame)).toBeNull();
expect(frame.stack[0]).toBe(0xFF00n);
});
it('multiplies by power of 2', () => {
const frame = createFrame({ stack: [3n, 5n] });
expect(shl(frame)).toBeNull();
expect(frame.stack[0]).toBe(40n); // 5 * 2^3
});
it('handles zero shift (identity)', () => {
const value = 0x123456n;
const frame = createFrame({ stack: [0n, value] });
expect(shl(frame)).toBeNull();
expect(frame.stack[0]).toBe(value);
});
it('returns 0 for shift >= 256', () => {
const frame = createFrame({ stack: [256n, 0xFFFFFFFFn] });
expect(shl(frame)).toBeNull();
expect(frame.stack[0]).toBe(0n);
});
it('handles partial overflow', () => {
const value = 0xFFn;
const frame = createFrame({ stack: [252n, value] });
expect(shl(frame)).toBeNull();
// 0xFF << 252 = 0xFF00...0000 (252 zeros)
const expected = 0xFFn << 252n;
expect(frame.stack[0]).toBe(expected);
});
it('shifts MAX value by 1', () => {
const MAX = (1n << 256n) - 1n;
const frame = createFrame({ stack: [1n, MAX] });
expect(shl(frame)).toBeNull();
// All bits except LSB
expect(frame.stack[0]).toBe(MAX - 1n);
});
it('shifts 1 to MSB position', () => {
const frame = createFrame({ stack: [255n, 1n] });
expect(shl(frame)).toBeNull();
expect(frame.stack[0]).toBe(1n << 255n);
});
it('returns InvalidOpcode before Constantinople', () => {
const frame = createFrame({
stack: [8n, 0xFFn],
hardfork: 'byzantium'
});
expect(shl(frame)).toEqual({ type: 'InvalidOpcode' });
});
it('returns StackUnderflow with insufficient stack', () => {
const frame = createFrame({ stack: [8n] });
expect(shl(frame)).toEqual({ type: 'StackUnderflow' });
});
it('returns OutOfGas when insufficient gas', () => {
const frame = createFrame({ stack: [8n, 0xFFn], gasRemaining: 2n });
expect(shl(frame)).toEqual({ type: 'OutOfGas' });
});
});