src/account/decimal.test.ts
v0.3.0 · 2.4 KB
import { describe, expect, it } from 'vitest';
import * as D from './decimal.js';
const s = (x: string) => {
const d = D.parseDec(x);
if (!d) throw new Error(`bad fixture ${x}`);
return d;
};
describe('decimal (private exact arithmetic)', () => {
it('accepts strict decimal strings only', () => {
for (const ok of ['0', '1', '-0.5', '123.4500', '0.00000001', '-999999.99999999']) {
expect(D.parseDec(ok)).not.toBeNull();
}
for (const bad of [' 100', '100 ', 'abc', '1e5', '+1', '1.', '.5', '', '--1', '1,5', 'NaN', 'Infinity']) {
expect(D.parseDec(bad)).toBeNull();
}
expect(D.parseDec(1)).toBeNull();
expect(D.parseDec(null)).toBeNull();
expect(D.parseDec(undefined)).toBeNull();
});
it('adds without binary float error', () => {
expect(D.toDecString(D.add(s('0.1'), s('0.2')))).toBe('0.3');
expect(D.toNumber(D.add(s('0.1'), s('0.2')))).toBe(0.3);
let acc = D.ZERO;
for (let i = 0; i < 10; i++) acc = D.add(acc, s('0.1'));
expect(D.toDecString(acc)).toBe('1');
});
it('subtracts, compares and takes max/abs/sign across scales', () => {
expect(D.toDecString(D.sub(s('1000'), s('200.25')))).toBe('799.75');
expect(D.cmp(s('1.10'), s('1.1'))).toBe(0);
expect(D.cmp(s('-2'), s('1.5'))).toBe(-1);
expect(D.cmp(s('2'), s('1.99999999'))).toBe(1);
expect(D.toDecString(D.max(D.ZERO, s('-3')))).toBe('0');
expect(D.toDecString(D.abs(s('-3.5')))).toBe('3.5');
expect(D.sign(s('-0.0'))).toBe(0);
expect(D.sign(s('-0.01'))).toBe(-1);
expect(D.isZero(s('0.000'))).toBe(true);
});
it('prints canonical strings', () => {
expect(D.toDecString(s('100.500'))).toBe('100.5');
expect(D.toDecString(s('-0.000'))).toBe('0');
expect(D.toDecString(s('0.05'))).toBe('0.05');
expect(D.toDecString(s('-12.340'))).toBe('-12.34');
});
it('shifts left exactly (rate to bps)', () => {
expect(D.toDecString(D.shiftLeft(s('0.00015'), 4))).toBe('1.5');
expect(D.toDecString(D.shiftLeft(s('-0.00003'), 4))).toBe('-0.3');
expect(D.toDecString(D.shiftLeft(s('2'), 4))).toBe('20000');
expect(() => D.shiftLeft(s('1'), -1)).toThrow(RangeError);
});
it('converts finite numbers with bounded scale', () => {
expect(D.toDecString(D.decFromNumber(12.5) as D.Dec)).toBe('12.5');
expect(D.decFromNumber(Number.NaN)).toBeNull();
expect(D.decFromNumber(Number.POSITIVE_INFINITY)).toBeNull();
});
});