src/orders/cloid.test.ts
v0.3.0 · 3 KB
import { describe, expect, it } from 'vitest';
import { CLOID_HEX_LENGTH, cloidHasPrefix, createCloid, isCloid, normalizeCloid } from './cloid.js';
import { nonNegativeDiff, plain, dec } from './decimal.js';
import { HlOrderError } from './errors.js';
const fixed = (byte: number) => (bytes: Uint8Array) => bytes.fill(byte);
describe('cloid format: 0x + 32 hex', () => {
it('isCloid accepts exactly 34 characters of hex, either case', () => {
expect(isCloid(`0x${'a'.repeat(32)}`)).toBe(true);
expect(isCloid(`0x${'A'.repeat(32)}`)).toBe(true);
expect(isCloid('0x1234')).toBe(false); // SDK: "Invalid length: Expected 34"
expect(isCloid(`0x${'a'.repeat(33)}`)).toBe(false);
expect(isCloid(`${'a'.repeat(34)}`)).toBe(false);
expect(isCloid(`0x${'g'.repeat(32)}`)).toBe(false);
expect(isCloid(123)).toBe(false);
});
it('normalizeCloid lowercases (the SDK signs and the exchange echoes lowercase)', () => {
expect(normalizeCloid(`0x${'AbCd'.repeat(8)}`)).toBe(`0x${'abcd'.repeat(8)}`);
expect(() => normalizeCloid('0x1234')).toThrow(HlOrderError);
});
});
describe('createCloid', () => {
it('produces a valid lowercase cloid from the random source', () => {
const c = createCloid({ random: fixed(0xab) });
expect(c).toBe(`0x${'ab'.repeat(16)}`);
expect(c.length).toBe(2 + CLOID_HEX_LENGTH);
});
it('uses crypto by default and does not repeat', () => {
const seen = new Set(Array.from({ length: 200 }, () => createCloid()));
expect(seen.size).toBe(200);
for (const c of seen) expect(isCloid(c)).toBe(true);
});
it('places an ownership prefix at the start, keeping the length', () => {
const c = createCloid({ prefix: '0xBEEF', random: fixed(0) });
expect(c).toBe(`0xbeef${'0'.repeat(28)}`);
expect(cloidHasPrefix(c, 'beef')).toBe(true);
expect(cloidHasPrefix(c, 'dead')).toBe(false);
expect(cloidHasPrefix('0x12', 'beef')).toBe(false);
});
it('rejects a prefix that is not hex or leaves fewer than 16 random characters', () => {
expect(() => createCloid({ prefix: 'xyz' })).toThrow(HlOrderError);
expect(() => createCloid({ prefix: 'a'.repeat(17) })).toThrow(/prefix/);
expect(createCloid({ prefix: 'a'.repeat(16) })).toMatch(/^0xa{16}[0-9a-f]{16}$/);
});
it('rejects a random source that returns the wrong length', () => {
expect(() => createCloid({ random: () => new Uint8Array(4) })).toThrow(RangeError);
});
});
describe('exact decimal helpers', () => {
it('remaining size has no float noise', () => {
expect(0.3 - 0.1).not.toBe(0.2);
expect(nonNegativeDiff('0.3', '0.1')).toBe('0.2');
expect(nonNegativeDiff('1', '1.000')).toBe('0');
expect(nonNegativeDiff('1', '2')).toBe('0');
expect(nonNegativeDiff(0.29, '0.001')).toBe('0.289');
});
it('plain renders small, negative and integer values canonically', () => {
expect(plain({ n: 5n, s: 4 })).toBe('0.0005');
expect(plain({ n: -1234n, s: 2 })).toBe('-12.34');
expect(plain({ n: 1200n, s: 2 })).toBe('12');
expect(plain(dec('-0'))).toBe('0');
});
});