import { describe, expect, it, vi } from "vitest"; import { TOOLCRAFT_ADVERTISED_MODEL_FORMATS } from "../model-import/formats/production-model-format-registry"; import { defineToolcraft } from "./define-toolcraft"; import type { ToolcraftControlSchema, ToolcraftModelFormat, ToolcraftModelImportLimits, ToolcraftModelTopologyProfile, } from "./types"; import { createFileDropSchema, getSourceControl, } from "./define-toolcraft.control-sections.test-support"; describe("defineToolcraft fileDrop normalization", () => { it("defaults model topology to the realtime mesh profile", () => { const app = defineToolcraft( createFileDropSchema({ assetKind: "model" }), ); expect(getSourceControl(app)?.topologyProfile).toBe("realtime-mesh"); }); it("exposes required resolved model fields after assetKind narrowing", () => { const app = defineToolcraft( createFileDropSchema({ assetKind: "model" }), ); const control = getSourceControl(app); if (control?.assetKind !== "model") { throw new Error("Expected a resolved model fileDrop control."); } const requiredFields: readonly [ readonly ToolcraftModelFormat[], ToolcraftModelImportLimits, false, ToolcraftModelTopologyProfile, ] = [ control.modelFormats, control.modelLimits, control.multiple, control.topologyProfile, ]; expect(requiredFields[0]).toEqual(TOOLCRAFT_ADVERTISED_MODEL_FORMATS); expect(requiredFields[1].maxNodes).toBeGreaterThan(0); expect(requiredFields[2]).toBe(false); expect(requiredFields[3]).toBe("realtime-mesh"); }); it("defaults and narrows model formats against the advertised adapter registry", () => { const defaultApp = defineToolcraft( createFileDropSchema({ assetKind: "model" }), ); const narrowedApp = defineToolcraft( createFileDropSchema({ assetKind: "model", modelFormats: ["glb", "gltf"], }), ); expect(getSourceControl(defaultApp)?.modelFormats).toEqual( TOOLCRAFT_ADVERTISED_MODEL_FORMATS, ); expect(getSourceControl(narrowedApp)?.modelFormats).toEqual(["glb", "gltf"]); expect( getSourceControl( defineToolcraft( createFileDropSchema({ assetKind: "model", modelFormats: ["obj"], }), ), )?.modelFormats, ).toEqual(["obj"]); expect(() => defineToolcraft( createFileDropSchema({ assetKind: "model", modelFormats: ["dae"], }), ), ).toThrow(/model fileDrop.*unsupported model format.*dae/u); }); it.each([ ["an undefined entry", ["glb", undefined]], [ "a sparse entry", (() => { const formats: unknown[] = ["glb"]; formats.length = 2; return formats; })(), ], ])("rejects modelFormats containing %s", (_label, modelFormats) => { expect(() => defineToolcraft( createFileDropSchema({ assetKind: "model", modelFormats, }), ), ).toThrow(/model fileDrop.*modelFormats/u); }); it("snapshots validated modelFormats without invoking the input iterator", () => { const modelFormats = ["glb", "gltf"]; const adversarialIterator = vi.fn(function* () { yield "dae"; }); Object.defineProperty(modelFormats, Symbol.iterator, { configurable: true, value: adversarialIterator, }); const app = defineToolcraft( createFileDropSchema({ assetKind: "model", modelFormats }), ); expect(getSourceControl(app)?.modelFormats).toEqual(["glb", "gltf"]); expect(adversarialIterator).not.toHaveBeenCalled(); }); it("snapshots stateful control branch fields before validation", () => { let assetKindReads = 0; let ownKeysCalls = 0; let typeReads = 0; const statefulControl = new Proxy( { assetKind: "model", target: "source.model", type: "fileDrop", }, { get(target, property, receiver) { if (property === "assetKind") { assetKindReads += 1; return assetKindReads === 1 ? "model" : "image"; } if (property === "type") { typeReads += 1; return typeReads === 1 ? "fileDrop" : "panelActions"; } return Reflect.get(target, property, receiver); }, ownKeys(target) { ownKeysCalls += 1; return Reflect.ownKeys(target); }, }, ) as unknown as ToolcraftControlSchema; const app = defineToolcraft({ canvas: { enabled: true }, panels: { controls: { sections: [ { controls: { source: statefulControl }, title: "Source", }, ], title: "Controls", }, }, }); const normalizedControl = getSourceControl(app); expect(normalizedControl?.assetKind).toBe("model"); expect(normalizedControl?.type).toBe("fileDrop"); expect(ownKeysCalls).toBe(1); expect(assetKindReads).toBe(1); expect(typeReads).toBe(1); }); });