font.test.js

2.6 kB · javascript · 59 lines

1import { expect, test } from 'bun:test';2import { existsSync } from 'node:fs';3import { join } from 'node:path';4import { animate, cycle, letters, merge, HOLD } from './font.js';5import FONT from './font.json' with { type: 'json' };67const WORDMARK = 'MRLYPROD';8const PKG = join(import.meta.dir, '..', '..', 'pkg');9const HAS = existsSync(join(PKG, 'mrlydemo.js'));1011test.skipIf(!HAS)('the wordmark writes itself in stroke order, one cell a frame', () => {12  const write = animate(WORDMARK, 1);13  expect([write.rows, write.cols, write.fps]).toEqual([7, 49, 25]);14  expect(write.frames[0]).toEqual([]);15  expect(write.frames.length).toBe(104);16  for (let i = 1; i < write.frames.length; i++) expect(write.frames[i].length).toBe(write.frames[i - 1].length + 1);17  expect(write.frames[1]).toEqual([5 * 49 + 1]);18  const grid = letters(WORDMARK).grid;19  const lit = grid.flat().filter(Boolean).length;20  expect(write.frames[103].length).toBe(lit);21});2223test.skipIf(!HAS)('the eight letters fold into an X in twenty-two frames', () => {24  const folded = merge(WORDMARK, 1);25  expect(folded.length).toBe(22);26  expect(folded[0]).toEqual(animate(WORDMARK, 1).frames[103]);27  const x = [];28  FONT.X.rows.forEach((row, r) => [...row].forEach((ch, c) => ch === '1' && x.push((1 + r) * 49 + 22 + c)));29  expect(folded[21]).toEqual(x);30});3132test.skipIf(!HAS)('the cycle loops through both halves with a rest after each', () => {33  const anim = cycle(WORDMARK, 1);34  expect(anim.frames.length).toBe(2 * 104 + 2 * 22 + 4 * HOLD);35  expect(anim.frames.length).toBe(352);36  for (const frame of anim.frames) {37    expect(frame.every((v, i) => i === 0 || frame[i - 1] < v)).toBe(true);38    expect(frame.every((v) => v < anim.rows * anim.cols)).toBe(true);39  }40});4142test.skipIf(!HAS)('any string writes itself and a lone glyph has nothing to merge', () => {43  for (const text of ['a', 'hi', 'mrly.net', '(1)']) {44    const write = animate(text, 2);45    const { rows, cols, grid } = letters(text);46    expect([write.rows, write.cols]).toEqual([rows + 4, cols + 4]);47    expect(write.frames.length).toBe(grid.flat().filter(Boolean).length + 1);48  }49  expect(merge('A', 1).length).toBe(1);50});5152test.skipIf(!HAS)('the kit matches the crate frame for frame', async () => {53  const wasm = await import(join(PKG, 'mrlydemo.js'));54  await wasm.default({ module_or_path: await Bun.file(join(PKG, 'mrlydemo_bg.wasm')).arrayBuffer() });55  for (const text of ['MRLYPROD', 'SIERPINSKI', 'mrly.net', '(1)', 'Hi 42', 'A']) {56    expect(animate(text, 1)).toEqual(JSON.parse(wasm.font_animate(text, 1)));57    expect(cycle(text, 1, 25)).toEqual(JSON.parse(wasm.font_cycle(text, 1, 25)));58  }59});