import { describe, expect, it } from 'vitest'; import { buildCybersigil, GLYPHS } from './cybersigil'; /** Deterministic LCG so a given seed reproduces a given sigil. */ function seeded(seed: number): () => number { let s = seed >>> 0; return () => { s = (s * 1664525 + 1013904223) >>> 0; return s / 4294967296; }; } describe('buildCybersigil', () => { it('is deterministic for a fixed RNG', () => { const a = buildCybersigil({ rng: seeded(42) }); const b = buildCybersigil({ rng: seeded(42) }); expect(a).toBe(b); }); it('varies with the seed', () => { expect(buildCybersigil({ rng: seeded(1) })).not.toBe(buildCybersigil({ rng: seeded(2) })); }); it('emits a single well-formed root svg', () => { const svg = buildCybersigil({ rng: seeded(7) }); expect(svg.startsWith('')).toBe(true); expect(svg.match(/ { const svg = buildCybersigil({ rng: seeded(7) }); expect(svg.match(/class="cs-sig-half"/g)).toHaveLength(2); expect(svg).toContain('transform="scale(-1 1)"'); }); it('every stroke is pathLength-normalised for the carve animation', () => { const svg = buildCybersigil({ rng: seeded(99) }); const paths = svg.match(/]*>/g) ?? []; expect(paths.length).toBeGreaterThan(0); for (const p of paths) expect(p).toContain('pathLength="1"'); }); it('exposes a numeric, positive viewBox', () => { const svg = buildCybersigil({ rng: seeded(7) }); const vb = svg.match(/viewBox="([^"]+)"/)?.[1] ?? ''; const nums = vb.split(/\s+/).map(Number); expect(nums).toHaveLength(4); expect(nums.every(Number.isFinite)).toBe(true); expect(nums[2]).toBeGreaterThan(0); // width expect(nums[3]).toBeGreaterThan(0); // height }); it('honours the count option and stays bounded', () => { const sparse = buildCybersigil({ count: 1, rng: seeded(5) }); const dense = buildCybersigil({ count: 9, rng: seeded(5) }); const n = (s: string) => (s.match(/ { expect(GLYPHS.length).toBeGreaterThan(0); for (const g of GLYPHS) { expect(g.w).toBeGreaterThan(0); expect(g.h).toBeGreaterThan(0); expect(g.d).toMatch(/^M/); } }); });