Skip to content
markpaper

src/numbers/numbers.test.ts

v0.1.0 · 1.7 KB

Download file
import { describe, expect, it } from 'vitest';
import {
  decAdd,
  decFromNumber,
  decToString,
  isOnStep,
  parseDec,
  parseLossless,
  snapToGrid,
  snapToStep,
  stepsOf,
} from './index.js';

describe('exact decimals and lossless JSON', () => {
  it('preserves numeric tokens and escaped string contents', () => {
    expect(parseLossless('{"id":9007199254741009,"quantity":1.500,"small":2e-9,"text":"1.5 \\" token"}')).toEqual({
      id: '9007199254741009',
      quantity: '1.500',
      small: '2e-9',
      text: '1.5 " token',
    });
  });
  it.each(['{1:2}', '{"a":01}', '[1e]', '[1.2.3]'])('rejects invalid JSON %s', (text) => {
    expect(() => parseLossless(text)).toThrow();
  });
  it('does not lose an exact lot to binary division', () => {
    expect(stepsOf(parseDec('0.57')!, parseDec('0.01')!, 'floor')).toBe(57n);
    expect(decToString(snapToStep(decFromNumber(0.5799999999999998)!, parseDec('0.02')!, 'floor', 'float'))).toBe(
      '0.58',
    );
  });
  it('rounds negative halves away from zero and remains on grid', () => {
    const step = parseDec('0.2')!;
    const value = snapToStep(parseDec('-0.7')!, step, 'nearest');
    expect(decToString(value)).toBe('-0.8');
    expect(isOnStep(value, step)).toBe(true);
  });
  it('adds different scales exactly and rejects abusive exponents', () => {
    expect(decToString(decAdd(parseDec('7.20')!, parseDec('0.008')!))).toBe('7.208');
    expect(parseDec('1e9999')).toBeNull();
  });
  it('distinguishes double print noise from a real off-grid position', () => {
    expect(snapToGrid(parseDec('0.38000000000000006')!, parseDec('0.02')!).noise).toBe(true);
    expect(snapToGrid(parseDec('0.387')!, parseDec('0.02')!).noise).toBe(false);
  });
});
All files