From 8f8f6894afe52dee8abd5693f6a46978b70c9eaf Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Sun, 5 Apr 2026 02:32:54 +0200 Subject: [PATCH] Update tests for collider and geometry changes --- tests/domain/build-runtime-scene.test.ts | 60 +++++++++---------- tests/geometry/box-brush-geometry.test.ts | 37 ++++++++++++ .../serialization/scene-document-json.test.ts | 30 ++++++++++ 3 files changed, 95 insertions(+), 32 deletions(-) diff --git a/tests/domain/build-runtime-scene.test.ts b/tests/domain/build-runtime-scene.test.ts index 89ee9a81..04f82975 100644 --- a/tests/domain/build-runtime-scene.test.ts +++ b/tests/domain/build-runtime-scene.test.ts @@ -301,40 +301,36 @@ describe("buildRuntimeSceneFromDocument", () => { z: 0 }); expect(runtimeScene.brushes[0].faces.posY.material?.id).toBe("starter-concrete-checker"); - expect(runtimeScene.colliders).toEqual([ - { - kind: "box", - source: "brush", - brushId: "brush-room-floor", - center: { - x: 0, - y: -0.5, - z: 0 + expect(runtimeScene.colliders).toHaveLength(1); + expect(runtimeScene.colliders[0]).toMatchObject({ + kind: "trimesh", + source: "brush", + brushId: "brush-room-floor", + center: { + x: 0, + y: -0.5, + z: 0 + }, + rotationDegrees: { + x: 0, + y: 0, + z: 0 + }, + worldBounds: { + min: { + x: -4, + y: -1, + z: -4 }, - rotationDegrees: { - x: 0, + max: { + x: 4, y: 0, - z: 0 - }, - size: { - x: 8, - y: 1, - z: 8 - }, - worldBounds: { - min: { - x: -4, - y: -1, - z: -4 - }, - max: { - x: 4, - y: 0, - z: 4 - } + z: 4 } } - ]); + }); + expect(Array.from(runtimeScene.colliders[0].vertices)).toHaveLength(24); + expect(Array.from(runtimeScene.colliders[0].indices)).toHaveLength(36); expect(runtimeScene.sceneBounds).toEqual({ min: { x: -4, @@ -689,11 +685,11 @@ describe("buildRuntimeSceneFromDocument", () => { size: brush.size }); expect(runtimeScene.colliders[0]).toMatchObject({ + kind: "trimesh", source: "brush", brushId: brush.id, center: brush.center, - rotationDegrees: brush.rotationDegrees, - size: brush.size + rotationDegrees: brush.rotationDegrees }); expect(runtimeScene.sceneBounds?.min.x).toBeCloseTo(-0.8713203436); expect(runtimeScene.sceneBounds?.max.x).toBeCloseTo(3.3713203436); diff --git a/tests/geometry/box-brush-geometry.test.ts b/tests/geometry/box-brush-geometry.test.ts index 99f5ff56..5bdf6a56 100644 --- a/tests/geometry/box-brush-geometry.test.ts +++ b/tests/geometry/box-brush-geometry.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest"; import { createBoxBrush } from "../../src/document/brushes"; import { getBoxBrushBounds, getBoxBrushCornerPositions } from "../../src/geometry/box-brush"; +import { buildBoxBrushDerivedMeshData, validateBoxBrushGeometry } from "../../src/geometry/box-brush-mesh"; describe("box brush geometry", () => { it("builds finite bounds and eight corner positions from canonical box data", () => { @@ -67,4 +68,40 @@ describe("box brush geometry", () => { expect(corners).toHaveLength(8); expect(new Set(corners.map((corner) => `${corner.x}:${corner.y}:${corner.z}`)).size).toBe(8); }); + + it("triangulates non-planar quad faces deterministically from authored whitebox geometry", () => { + const brush = createBoxBrush(); + brush.geometry.vertices.posX_posY_posZ.z += 0.75; + brush.size = { + x: 2, + y: 2, + z: 2.75 + }; + + const diagnostics = validateBoxBrushGeometry(brush); + const derivedMesh = buildBoxBrushDerivedMeshData(brush); + + expect(diagnostics).toEqual([]); + expect(derivedMesh.faceSurfaces).toHaveLength(6); + expect(derivedMesh.faceSurfaces.every((surface) => surface.triangles).flat()).toHaveLength(12); + expect(Array.from(derivedMesh.colliderIndices)).toHaveLength(36); + }); + + it("reports degenerate authored whitebox faces clearly", () => { + const brush = createBoxBrush(); + const collapsedVertex = { x: 1, y: 1, z: 1 }; + brush.geometry.vertices.negX_posY_posZ = collapsedVertex; + brush.geometry.vertices.posX_posY_posZ = collapsedVertex; + brush.geometry.vertices.posX_posY_negZ = collapsedVertex; + brush.geometry.vertices.negX_posY_negZ = collapsedVertex; + + expect(validateBoxBrushGeometry(brush)).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + code: "degenerate-box-face", + faceId: "posY" + }) + ]) + ); + }); }); diff --git a/tests/serialization/scene-document-json.test.ts b/tests/serialization/scene-document-json.test.ts index 203a373b..e9723390 100644 --- a/tests/serialization/scene-document-json.test.ts +++ b/tests/serialization/scene-document-json.test.ts @@ -141,6 +141,36 @@ describe("scene document JSON", () => { expect(parseSceneDocumentJson(serializeSceneDocument(document))).toEqual(document); }); + it("round-trips authored whitebox geometry vertices", () => { + const brush = createBoxBrush({ + id: "brush-authored-geometry" + }); + brush.geometry.vertices.posX_posY_posZ = { + x: 1.5, + y: 1, + z: 1.25 + }; + brush.geometry.vertices.negX_negY_negZ = { + x: -1, + y: -1.25, + z: -1.5 + }; + brush.size = { + x: 2.5, + y: 2.25, + z: 2.75 + }; + + const document = { + ...createEmptySceneDocument({ name: "Authored Geometry Scene" }), + brushes: { + [brush.id]: brush + } + }; + + expect(parseSceneDocumentJson(serializeSceneDocument(document))).toEqual(document); + }); + it("round-trips authored world environment settings", () => { const document = createEmptySceneDocument({ name: "World Environment Scene" }); document.world.background = {