import { describe, expect, it } from "vitest"; import { canvasEditingModule } from "./built-ins/canvas-editing/canvas-editing-module"; import { layersModule } from "./built-ins/layers/layers-module"; import { mediaSourceModule } from "./built-ins/media-source/media-source-module"; import { model3dModule } from "./built-ins/model-3d/model-3d-module"; import { spatialViewModule } from "./built-ins/spatial-view/spatial-view-module"; import type { ToolcraftProductIntegrationPortId, ToolcraftProductIntegrationPortRequirement, } from "./contract/integration-port"; import type { ToolcraftProductModuleId } from "./contract/capability"; import type { ToolcraftProductModuleDefinition } from "./contract/module-definition"; import { resolveToolcraftProductModules } from "./testing/module-resolution-test-support"; import { getToolcraftModulePortErrors } from "./resolution/validate-module-ports"; import { permutations } from "./testing/module-contribution-test-fixtures"; type IsExact = (() => Value extends Left ? 1 : 2) extends < Value, >() => Value extends Right ? 1 : 2 ? true : false; const applicabilityContractIsClosed: IsExact< ToolcraftProductIntegrationPortRequirement["applicability"], "always" | "product-scene" | "spatial-product-scene" > = true; void applicabilityContractIsClosed; const integrationPortContractIsClosed: IsExact< ToolcraftProductIntegrationPortId, | "modelPresentation" | "scene.canvasContent" | "scene.rasterFrameRenderer" | "scene.vectorFrameRenderer" > = true; void integrationPortContractIsClosed; // @ts-expect-error The provisional canvas-interaction port was removed. const legacyCanvasInteractionPort: ToolcraftProductIntegrationPortId = "canvasInteraction"; // @ts-expect-error The provisional entities port was removed. const legacyEntitiesPort: ToolcraftProductIntegrationPortId = "entities"; // @ts-expect-error The provisional spatial-view port was removed. const legacySpatialViewPort: ToolcraftProductIntegrationPortId = "spatialView"; void legacyCanvasInteractionPort; void legacyEntitiesPort; void legacySpatialViewPort; const projectBPorts = [ "modelPresentation", "scene.canvasContent", ] as const satisfies readonly ToolcraftProductIntegrationPortId[]; const consumersByPort = { modelPresentation: ["model-3d"], "scene.canvasContent": ["canvas-editing", "spatial-view"], } as const satisfies Readonly< Record<(typeof projectBPorts)[number], readonly ToolcraftProductModuleId[]> >; const projectBDefinitions = [ canvasEditingModule(), layersModule(), mediaSourceModule(), model3dModule({ presentation: "custom" }), spatialViewModule(), ]; function resolvePlan( definitions: readonly ToolcraftProductModuleDefinition[] = projectBDefinitions, ) { return resolveToolcraftProductModules(definitions).plan; } describe("Project B module port validation", () => { it("accepts the complete exact set of provided Project B ports", () => { const plan = resolvePlan(); expect( getToolcraftModulePortErrors({ plan, productSceneRequired: false, provided: new Set(projectBPorts), spatialProductSceneRequired: false, }), ).toEqual([]); expect( getToolcraftModulePortErrors({ plan, productSceneRequired: true, provided: new Set(projectBPorts), spatialProductSceneRequired: true, }), ).toEqual([]); expect( plan.portRequirements.map(({ applicability }) => applicability), ).toEqual(["always", "always"]); }); it.each(projectBPorts)( "reports a stable error when %s is missing", (missingPort) => { const provided = new Set(projectBPorts.filter((id) => id !== missingPort)); expect( getToolcraftModulePortErrors({ plan: resolvePlan(), productSceneRequired: false, provided, spatialProductSceneRequired: false, }), ).toEqual([ `Toolcraft integration port "${missingPort}" is missing; applicability "always" requires it for consumers: ${[...consumersByPort[missingPort]].sort().join(", ")}. Expected public field "ports.${missingPort}".`, ]); }, ); it("reports an unused gated custom model-presentation port", () => { expect( getToolcraftModulePortErrors({ plan: resolvePlan([mediaSourceModule()]), productSceneRequired: false, provided: new Set(["modelPresentation"]), spatialProductSceneRequired: false, }), ).toEqual([ 'Toolcraft integration port "modelPresentation" is provided but unused; no resolved module consumes it. Public field "ports.modelPresentation" is not applicable.', ]); }); it("accepts core-consumed static canvas content without an interaction module", () => { expect( getToolcraftModulePortErrors({ plan: resolvePlan([mediaSourceModule()]), productSceneRequired: true, provided: new Set(["scene.canvasContent"]), spatialProductSceneRequired: false, }), ).toEqual([]); }); it("requires canvas content for Canvas Editing and procedural Spatial View", () => { expect( getToolcraftModulePortErrors({ plan: resolvePlan([canvasEditingModule()]), productSceneRequired: false, provided: new Set(), spatialProductSceneRequired: false, }), ).toEqual([ 'Toolcraft integration port "scene.canvasContent" is missing; applicability "always" requires it for consumers: canvas-editing. Expected public field "ports.scene.canvasContent".', ]); expect( getToolcraftModulePortErrors({ plan: resolvePlan([spatialViewModule()]), productSceneRequired: false, provided: new Set(), spatialProductSceneRequired: true, }), ).toEqual([ 'Toolcraft integration port "scene.canvasContent" is missing; applicability "spatial-product-scene" requires it because spatialProductSceneRequired is true for consumers: spatial-view. Expected public field "ports.scene.canvasContent".', ]); }); it("keeps runtime-presented Model 3D Spatial View port-free", () => { expect( getToolcraftModulePortErrors({ plan: resolvePlan([model3dModule(), spatialViewModule()]), productSceneRequired: false, provided: new Set(), spatialProductSceneRequired: false, }), ).toEqual([]); }); it("returns byte-identical sorted frozen errors for declaration and provided-order permutations", () => { const provided = [ "modelPresentation", ] as const satisfies readonly ToolcraftProductIntegrationPortId[]; const expected = [ 'Toolcraft integration port "scene.canvasContent" is missing; applicability "always" requires it for consumers: canvas-editing, spatial-view. Expected public field "ports.scene.canvasContent".', ].sort(); const expectedJson = JSON.stringify(expected); for (const declarationOrder of permutations(projectBDefinitions)) { const plan = resolvePlan(declarationOrder); for (const providedOrder of permutations(provided)) { const errors = getToolcraftModulePortErrors({ plan, productSceneRequired: true, provided: new Set(providedOrder), spatialProductSceneRequired: true, }); expect(JSON.stringify(errors)).toBe(expectedJson); expect(errors).toEqual([...errors].sort()); expect(Object.isFrozen(errors)).toBe(true); } } }); });