| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
- import { tmpdir } from "node:os";
- import { join } from "node:path";
- import { describe, expect, it } from "vitest";
- import {
- ContentLoader,
- ContentRegistry,
- particleSchema,
- shaderSchema,
- type ParticleDef,
- type ShaderDef,
- } from "../src/index.js";
- async function setupLoader(): Promise<{ registry: ContentRegistry; loader: ContentLoader; tmp: string }> {
- const tmp = await mkdtemp(join(tmpdir(), "farm-particle-shader-"));
- await mkdir(join(tmp, "particles"), { recursive: true });
- await mkdir(join(tmp, "shaders"), { recursive: true });
- await writeFile(join(tmp, "particles", "dust.yaml"), "id: dust\nemitRate: 8\ncolors: ['#d7ccc8']\n");
- await writeFile(join(tmp, "shaders", "rain-tint.yaml"), "id: rain-tint\nfilter: grayscale\nparams: { factor: 0.7 }\n");
- const registry = new ContentRegistry();
- const loader = new ContentLoader(registry);
- return { registry, loader, tmp };
- }
- describe("particle content kind", () => {
- it("loads and validates particle YAML from content/particles/", async () => {
- const { registry, loader, tmp } = await setupLoader();
- try {
- const report = await loader.load(tmp);
- expect(report.ok).toBe(true);
- expect(registry.ids("particle")).toEqual(["dust"]);
- expect(registry.get<ParticleDef>("particle", "dust")).toEqual({ id: "dust", emitRate: 8, colors: ["#d7ccc8"] });
- } finally {
- await rm(tmp, { recursive: true, force: true });
- }
- });
- it("rejects an invalid particle def (bad color, negative speed, strict keys)", () => {
- expect(particleSchema.safeParse({ id: "bad", colors: ["green"] }).success).toBe(false);
- expect(particleSchema.safeParse({ id: "bad", speed: { min: -1, max: 1 } }).success).toBe(false);
- expect(particleSchema.safeParse({ id: "bad", emitRate: 0 }).success).toBe(false);
- expect(particleSchema.safeParse({ id: "bad", extra: true }).success).toBe(false);
- });
- it("accepts an empty (defaults-only) def and a fully-specified def", () => {
- expect(particleSchema.safeParse({ id: "plain" }).success).toBe(true);
- expect(
- particleSchema.safeParse({
- id: "rain",
- emitRate: 24,
- lifetime: { min: 600, max: 1000 },
- speed: { min: 240, max: 360 },
- angle: 90,
- spread: 8,
- gravity: 220,
- size: { min: 1, max: 2 },
- colors: ["#64b5f6"],
- fade: true,
- }).success,
- ).toBe(true);
- });
- });
- describe("shader content kind", () => {
- it("loads and validates shader YAML from content/shaders/", async () => {
- const { registry, loader, tmp } = await setupLoader();
- try {
- const report = await loader.load(tmp);
- expect(report.ok).toBe(true);
- expect(registry.ids("shader")).toEqual(["rain-tint"]);
- expect(registry.get<ShaderDef>("shader", "rain-tint")).toEqual({
- id: "rain-tint",
- filter: "grayscale",
- params: { factor: 0.7 },
- });
- } finally {
- await rm(tmp, { recursive: true, force: true });
- }
- });
- it("rejects an invalid shader def (unknown filter, strict keys)", () => {
- expect(shaderSchema.safeParse({ id: "bad", filter: "vignette" }).success).toBe(false);
- expect(shaderSchema.safeParse({ id: "bad", filter: "blur", extra: true }).success).toBe(false);
- });
- it("accepts every built-in filter name", () => {
- for (const filter of ["blur", "tint", "grayscale", "sepia", "hue", "brightness"]) {
- expect(shaderSchema.safeParse({ id: "x", filter }).success).toBe(true);
- }
- });
- });
|