import type { Codec } from '@solana/kit'; import { FixedPoint } from '../src/fixed'; import { getI16F16Codec, getI8F56Codec, getU0F32Codec, getU16F16Codec, getU16F48Codec, getU18F14Codec, getU26F6Codec, getU32F32Codec, getU8F56Codec, getU8F8Codec, } from '../src/fixed/codecs'; type Case = { name: string; codec: () => Codec; value: number; fractionalBits: number; totalBits: number; signed: boolean; expectedRaw: bigint; expectedBytesLength: number; clamp?: boolean; }; const cases: Case[] = [ { name: 'U8F8', codec: getU8F8Codec, value: 12.5, fractionalBits: 8, totalBits: 16, signed: false, expectedRaw: (12_5n * 256n) / 10n, // 12.5 * 256 = 3200 expectedBytesLength: 2, }, { name: 'U16F16', codec: getU16F16Codec, value: 100.5, fractionalBits: 16, totalBits: 32, signed: false, expectedRaw: 6_586_368n, // Rust U16F16::from_num(100.5) expectedBytesLength: 4, }, { name: 'U18F14', codec: getU18F14Codec, value: 3.75, fractionalBits: 14, totalBits: 32, signed: false, expectedRaw: 61_440n, // 3.75 * 16384 expectedBytesLength: 4, }, { name: 'U26F6', codec: getU26F6Codec, value: 10.5, fractionalBits: 6, totalBits: 32, signed: false, expectedRaw: 672n, // 10.5 * 64 expectedBytesLength: 4, }, { name: 'U0F32', codec: getU0F32Codec, value: 0.5, fractionalBits: 32, totalBits: 32, signed: false, expectedRaw: 2_147_483_648n, // 0.5 * 2^32 expectedBytesLength: 4, }, { name: 'U16F48', codec: getU16F48Codec, value: 1.0, fractionalBits: 48, totalBits: 64, signed: false, expectedRaw: 1n << 48n, expectedBytesLength: 8, }, { name: 'U32F32', codec: getU32F32Codec, value: 1.5, fractionalBits: 32, totalBits: 64, signed: false, expectedRaw: 6_442_450_944n, // 1.5 * 2^32 expectedBytesLength: 8, }, { name: 'U8F56', codec: getU8F56Codec, value: 1.0, fractionalBits: 56, totalBits: 64, signed: false, expectedRaw: 1n << 56n, expectedBytesLength: 8, }, { name: 'I16F16', codec: getI16F16Codec, value: -2.75, fractionalBits: 16, totalBits: 32, signed: true, expectedRaw: -180_224n, // -2.75 * 65536 expectedBytesLength: 4, }, { name: 'I8F56', codec: getI8F56Codec, value: 1.0, fractionalBits: 56, totalBits: 64, signed: true, expectedRaw: 1n << 56n, expectedBytesLength: 8, }, { name: 'U8F8 clamp', codec: getU8F8Codec, value: 300.0, // exceeds max fractionalBits: 8, totalBits: 16, signed: false, expectedRaw: (1n << 16n) - 1n, // u16::MAX expectedBytesLength: 2, clamp: true, }, ]; describe('Fixed Point Golden Tests', () => { it.each(cases)('$name roundtrip matches raw', (c) => { const fp = FixedPoint.fromNumber(c.value, { fractionalBits: c.fractionalBits, totalBits: c.totalBits, signed: c.signed, }); expect(fp.raw).toBe(c.expectedRaw); const codec = c.codec(); const bytes = codec.encode(fp); expect(bytes).toHaveLength(c.expectedBytesLength); const decoded = codec.decode(bytes); expect(decoded.raw).toBe(c.expectedRaw); const num = decoded.toNumber(); if (c.clamp) { // For clamp cases, compare to the clamped raw scaled back. const scale = 1n << BigInt(c.fractionalBits); expect(num).toBeCloseTo(Number(c.expectedRaw) / Number(scale)); } else { expect(num).toBeCloseTo(c.value); } }); });