import { describe, expect, it } from "vitest"; import { imageExportModule } from "./built-ins/image-export/image-export-module"; import { svgExportModule } from "./built-ins/svg-export/svg-export-module"; import { timelineModule } from "./built-ins/timeline/timeline-module"; import { videoExportModule } from "./built-ins/video-export/video-export-module"; import type { ToolcraftProductModuleDefinition, ToolcraftProductModuleRecord, } from "./contract/module-definition"; import { resolveToolcraftModulePortRequirements } from "./resolution/resolve-product-modules"; import { resolveToolcraftProductModules } from "./testing/module-resolution-test-support"; import { createTestToolcraftProductModuleDefinition } from "./testing/create-test-module-definition"; import { permutations } from "./testing/module-contribution-test-fixtures"; const emptyTestModuleFields = { contributions: [], defaultProviders: [], requires: [], }; function assertPortResolutionRequiresOpaqueDefinitions( structuralRecord: ToolcraftProductModuleRecord, definition: ToolcraftProductModuleDefinition, ) { // @ts-expect-error Top-level product resolution requires opaque definitions. resolveToolcraftProductModules([structuralRecord]); // @ts-expect-error Port resolution requires opaque definitions. resolveToolcraftModulePortRequirements([structuralRecord]); resolveToolcraftModulePortRequirements([definition]); } void assertPortResolutionRequiresOpaqueDefinitions; describe("resolveToolcraftProductModules", () => { it("aggregates image and video into one sorted raster port requirement", () => { const resolution = resolveToolcraftProductModules([ videoExportModule(), imageExportModule(), ]); expect(resolution.plan.portRequirements).toEqual([ { applicability: "product-scene", consumers: ["image-export", "video-export"], id: "scene.rasterFrameRenderer", }, ]); }); it("resolves SVG into one always-applicable vector port requirement", () => { const resolution = resolveToolcraftProductModules([svgExportModule()]); expect(resolution.plan.portRequirements).toEqual([ { applicability: "always", consumers: ["svg-export"], id: "scene.vectorFrameRenderer", }, ]); }); it("returns byte-equal compact plans and materialized results for every declaration order", () => { const definitions = [ imageExportModule(), svgExportModule(), timelineModule({ mode: "playback" }), videoExportModule(), ]; const expected = resolveToolcraftProductModules(definitions); const expectedJson = JSON.stringify(expected); const expectedPlanJson = JSON.stringify(expected.plan); for (const declarationOrder of permutations(definitions)) { const resolution = resolveToolcraftProductModules(declarationOrder); expect(JSON.stringify(resolution)).toBe(expectedJson); expect(JSON.stringify(resolution.plan)).toBe(expectedPlanJson); } expect(Object.keys(expected.plan).sort()).toEqual([ "capabilities", "modules", "ownership", "portRequirements", ]); expect(expectedPlanJson).not.toContain('"definitions":'); expect(expectedPlanJson).not.toContain('"contributions":'); expect(expectedPlanJson).not.toContain('"controlSections":'); expect(expectedPlanJson).not.toContain('"panelActionsSection":'); expect(expectedPlanJson).not.toContain('"section":'); expect(expectedPlanJson).not.toContain('"role":'); }); it("returns frozen orchestration, materialization, plan, and port output", () => { const resolution = resolveToolcraftProductModules([ videoExportModule(), svgExportModule(), imageExportModule(), ]); expect(Object.isFrozen(resolution)).toBe(true); expect(Object.isFrozen(resolution.contributionResolution)).toBe(true); expect(Object.isFrozen(resolution.plan)).toBe(true); expect(Object.isFrozen(resolution.plan.portRequirements)).toBe(true); expect(resolution.plan.portRequirements.every(Object.isFrozen)).toBe(true); expect( resolution.plan.portRequirements.every(({ consumers }) => Object.isFrozen(consumers), ), ).toBe(true); }); it("lets always applicability absorb a conditional declaration with stable consumers", () => { const alwaysRaster = createTestToolcraftProductModuleDefinition({ ...emptyTestModuleFields, id: "image-export", portRequirements: [ { applicability: "always", id: "scene.rasterFrameRenderer", }, ], provides: ["artifact.image-export"], }); const productSceneRaster = createTestToolcraftProductModuleDefinition({ ...emptyTestModuleFields, id: "video-export", portRequirements: [ { applicability: "product-scene", id: "scene.rasterFrameRenderer", }, ], provides: ["artifact.video-export"], }); for (const declarationOrder of permutations([ productSceneRaster, alwaysRaster, ])) { expect( resolveToolcraftProductModules(declarationOrder).plan.portRequirements, ).toEqual([ { applicability: "always", consumers: ["image-export", "video-export"], id: "scene.rasterFrameRenderer", }, ]); } }); it("rejects independent conditional applicability atomically", () => { const productSceneRaster = createTestToolcraftProductModuleDefinition({ ...emptyTestModuleFields, id: "image-export", portRequirements: [ { applicability: "product-scene", id: "scene.rasterFrameRenderer", }, ], provides: ["artifact.image-export"], }); const spatialSceneRaster = createTestToolcraftProductModuleDefinition({ ...emptyTestModuleFields, id: "video-export", portRequirements: [ { applicability: "spatial-product-scene", id: "scene.rasterFrameRenderer", }, ], provides: ["artifact.video-export"], }); for (const declarationOrder of permutations([ spatialSceneRaster, productSceneRaster, ])) { expect(() => resolveToolcraftProductModules(declarationOrder)).toThrowError( 'Toolcraft integration port "scene.rasterFrameRenderer" has incompatible applicability declarations: image-export (product-scene), video-export (spatial-product-scene).', ); } }); it("resolves generic definition data without module-id feature behavior", () => { const imageWithVectorPort = createTestToolcraftProductModuleDefinition({ ...emptyTestModuleFields, id: "image-export", portRequirements: [ { applicability: "always", id: "scene.vectorFrameRenderer", }, ], provides: ["artifact.image-export"], }); const svgWithRasterPort = createTestToolcraftProductModuleDefinition({ ...emptyTestModuleFields, id: "svg-export", portRequirements: [ { applicability: "product-scene", id: "scene.rasterFrameRenderer", }, ], provides: ["artifact.svg-export"], }); expect( resolveToolcraftProductModules([ svgWithRasterPort, imageWithVectorPort, ]).plan.portRequirements, ).toEqual([ { applicability: "product-scene", consumers: ["svg-export"], id: "scene.rasterFrameRenderer", }, { applicability: "always", consumers: ["image-export"], id: "scene.vectorFrameRenderer", }, ]); }); });