161 lines
5.1 KiB
TypeScript
161 lines
5.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
import {
|
||
aliasToIconPx,
|
||
buildIngredientCoverSprite,
|
||
findAliasForIconPx,
|
||
foldAccents,
|
||
INGREDIENT_SPRITE_CELL,
|
||
isPreferredVariantAlias,
|
||
normalizeIngredientAliasKey,
|
||
parseIngredientSpritesBentext,
|
||
resolveIconPxForIngredientName
|
||
} from "./sprites.mjs";
|
||
|
||
describe("parseIngredientSpritesBentext", () => {
|
||
it("parse les blocs --- avec coordonnées et alias (| = synonymes)", () => {
|
||
const raw = `2 0
|
||
eau|vinaigre de riz|Vinaigre blanc
|
||
---
|
||
0 4
|
||
carnet
|
||
---
|
||
8 1
|
||
fromage
|
||
`;
|
||
const { byAlias, preferredAliases, csv } = parseIngredientSpritesBentext(raw);
|
||
|
||
// eau → (0, 64) ; carnet → (128, 0) ; fromage → (32, 256) — ligne 8 = preferred
|
||
expect(byAlias.eau).toEqual({ x: 0, y: 64, X: 0, Y: 64 });
|
||
expect(byAlias["vinaigre de riz"]).toEqual({ x: 0, y: 64, X: 0, Y: 64 });
|
||
expect(byAlias["vinaigre blanc"]).toEqual({ x: 0, y: 64, X: 0, Y: 64 });
|
||
expect(byAlias.carnet).toEqual({ x: 128, y: 0, X: 128, Y: 0 });
|
||
expect(byAlias.fromage).toEqual({ x: 32, y: 256, X: 32, Y: 256 });
|
||
|
||
expect(preferredAliases.has("fromage")).toBe(true);
|
||
expect(preferredAliases.has("eau")).toBe(false);
|
||
expect(preferredAliases.has("carnet")).toBe(false);
|
||
|
||
expect(csv).toContain("carnet");
|
||
expect(csv).toContain("fromage");
|
||
});
|
||
|
||
it("ignore un bloc sans coordonnées valides", () => {
|
||
const raw = `not_a_coord
|
||
eau
|
||
---
|
||
0 0
|
||
couvert
|
||
`;
|
||
const { byAlias } = parseIngredientSpritesBentext(raw);
|
||
expect(byAlias.eau).toBeUndefined();
|
||
expect(byAlias.couvert).toEqual({ x: 0, y: 0, X: 0, Y: 0 });
|
||
});
|
||
|
||
it("conserve la première définition en cas de conflit d’alias", () => {
|
||
const raw = `0 0
|
||
eau
|
||
---
|
||
1 0
|
||
eau
|
||
`;
|
||
const { byAlias } = parseIngredientSpritesBentext(raw);
|
||
expect(byAlias.eau).toEqual({ x: 0, y: 0, X: 0, Y: 0 });
|
||
});
|
||
|
||
it("retire le BOM et tolère CRLF entre blocs", () => {
|
||
const raw = "\uFEFF0 0\r\ncouvert\r\n---\r\n0 1\r\nassiette\r\n";
|
||
const { byAlias } = parseIngredientSpritesBentext(raw);
|
||
expect(byAlias.couvert).toBeDefined();
|
||
expect(byAlias.assiette).toBeDefined();
|
||
});
|
||
});
|
||
|
||
describe("resolveIconPxForIngredientName", () => {
|
||
const byAlias = {
|
||
riz: { x: 0, y: 0 },
|
||
"riz gluant": { x: 32, y: 0 },
|
||
avocat: { x: 64, y: 0 }
|
||
};
|
||
|
||
it("trouve l’alias direct", () => {
|
||
expect(resolveIconPxForIngredientName("riz", byAlias)).toEqual({ x: 0, y: 0 });
|
||
});
|
||
|
||
it("recherche sans accents", () => {
|
||
expect(resolveIconPxForIngredientName("AVOCAT", byAlias)).toEqual({ x: 64, y: 0 });
|
||
});
|
||
|
||
it("retombe sur l’alias le plus long en inclusion", () => {
|
||
expect(resolveIconPxForIngredientName("Riz gluant blanc", byAlias)).toEqual({ x: 32, y: 0 });
|
||
});
|
||
|
||
it("retourne null si pas de correspondance", () => {
|
||
expect(resolveIconPxForIngredientName("introuvable", byAlias)).toBeNull();
|
||
});
|
||
|
||
it("gère un nom composé avec / ou et (segments)", () => {
|
||
const local = { "eau": { x: 0, y: 0 }, "sel": { x: 32, y: 0 } };
|
||
expect(resolveIconPxForIngredientName("Sel / eau", local)).toEqual({ x: 32, y: 0 });
|
||
});
|
||
});
|
||
|
||
describe("aliasToIconPx", () => {
|
||
it("lit les coordonnées (x, y) ou (X, Y)", () => {
|
||
expect(aliasToIconPx({ a: { x: 1, y: 2 } }, "a")).toEqual({ x: 1, y: 2 });
|
||
expect(aliasToIconPx({ a: { X: 3, Y: 4 } }, "a")).toEqual({ x: 3, y: 4 });
|
||
});
|
||
|
||
it("retourne null si alias ou coords absentes", () => {
|
||
expect(aliasToIconPx({}, "x")).toBeNull();
|
||
expect(aliasToIconPx({ a: { x: "a", y: 2 } }, "a")).toBeNull();
|
||
});
|
||
});
|
||
|
||
describe("findAliasForIconPx", () => {
|
||
it("renvoie l’alias correspondant aux coordonnées exactes", () => {
|
||
const byAlias = { a: { x: 0, y: 0 }, b: { x: 32, y: 0 } };
|
||
expect(findAliasForIconPx(byAlias, { x: 32, y: 0 })).toBe("b");
|
||
expect(findAliasForIconPx(byAlias, { x: 100, y: 0 })).toBeNull();
|
||
});
|
||
});
|
||
|
||
describe("isPreferredVariantAlias", () => {
|
||
it("matche case-insensitive et tolère un set vide", () => {
|
||
const preferred = new Set(["fromage", "tomate"]);
|
||
expect(isPreferredVariantAlias(preferred, "Fromage")).toBe(true);
|
||
expect(isPreferredVariantAlias(preferred, "autre")).toBe(false);
|
||
expect(isPreferredVariantAlias(new Set(), "fromage")).toBe(false);
|
||
expect(isPreferredVariantAlias(preferred, "")).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe("buildIngredientCoverSprite", () => {
|
||
const sheet = { width: 512, height: 1024 };
|
||
|
||
it("renvoie null si coords ou sheet invalides", () => {
|
||
expect(buildIngredientCoverSprite(null, sheet)).toBeNull();
|
||
expect(buildIngredientCoverSprite({ x: 0, y: 0 }, null)).toBeNull();
|
||
});
|
||
|
||
it("calcule col/row depuis les pixels et fige sheet/cell", () => {
|
||
const result = buildIngredientCoverSprite({ x: 64, y: 256 }, sheet);
|
||
expect(result).toEqual({
|
||
sheet: "/ingredients.png",
|
||
col: 2,
|
||
row: 8,
|
||
cell: INGREDIENT_SPRITE_CELL,
|
||
sheetWidth: 512,
|
||
sheetHeight: 1024
|
||
});
|
||
});
|
||
});
|
||
|
||
describe("normalizeIngredientAliasKey & foldAccents", () => {
|
||
it("normalise espaces et casse", () => {
|
||
expect(normalizeIngredientAliasKey(" Riz gluant ")).toBe("riz gluant");
|
||
});
|
||
it("plie les accents", () => {
|
||
expect(foldAccents("Crème pâtissière")).toBe("creme patissiere");
|
||
});
|
||
});
|