added testing
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
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('<svg')).toBe(true);
|
||||
expect(svg.endsWith('</svg>')).toBe(true);
|
||||
expect(svg.match(/<svg/g)).toHaveLength(1);
|
||||
// no formatting holes leaked into the path data
|
||||
expect(svg).not.toMatch(/NaN|undefined|Infinity/);
|
||||
});
|
||||
|
||||
it('is vertically mirrored (two halves, one flipped about x=0)', () => {
|
||||
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(/<path\b[^>]*>/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(/<path/g) ?? []).length;
|
||||
expect(n(dense)).toBeGreaterThan(n(sparse));
|
||||
expect(n(dense)).toBeLessThanOrEqual(260); // MAX_PATHS(110) mirrored + ornaments
|
||||
});
|
||||
|
||||
it('ships a non-empty glyph library with valid path data', () => {
|
||||
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/);
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user