Newer
Older
rpg / apps / game / tools / pixelart / __tests__ / sizes.test.ts
import { readFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import { SIZES, SLOTS } from '../sizes.mjs';

/**
 * Реестр размеров (sizes.mjs) — единственный источник размеров спрайтов
 * для gen.mjs и lint-art.mjs. Здесь проверяется сам реестр и его
 * согласованность с фактическими ассетами (манифест AI-атласов).
 */

const here = dirname(fileURLToPath(import.meta.url));
const dim = (s: { w: number } | number[]) => (Array.isArray(s) ? `${s[0]}x${s[1]}` : `${s.w}x${s.h}`);

describe('реестр размеров спрайтов', () => {
    it('все группы дают валидные слоты «ширина x высота»', () => {
        for (const group of Object.values(SIZES)) {
            const sizes = 'w' in group ? [group] : Object.values(group);
            for (const s of sizes) {
                expect(dim(s as never)).toMatch(/^\d+x\d+$/);
            }
        }
    });

    it('базовые слоты арт-библии на месте', () => {
        for (const slot of ['32x16', '16x24', '20x20', '32x48', '32x56', '32x80', '64x80']) {
            expect(SLOTS.has(slot), slot).toBe(true);
        }
    });

    it('frameSize манифеста AI-атласов входит в слоты', () => {
        const manifest = JSON.parse(
            readFileSync(resolve(here, '../../aiart/atlas-manifest.json'), 'utf8')
        ) as Record<string, { frameSize?: [number, number] }>;
        for (const [id, entry] of Object.entries(manifest)) {
            const fs = entry.frameSize;
            if (!fs) continue;
            expect(SLOTS.has(`${fs[0]}x${fs[1]}`), id).toBe(true);
        }
    });
});