diff --git a/fission/.gitattributes b/fission/.gitattributes index 0bfa0baf18..fd0f18d791 100644 --- a/fission/.gitattributes +++ b/fission/.gitattributes @@ -1 +1,2 @@ public/assetpack.zip filter=lfs diff=lfs merge=lfs -text +src/test/**/*.snap binary linguist-generated=true diff --git a/fission/src/test/mirabuf/MirabufParser.test.ts b/fission/src/test/mirabuf/MirabufParser.test.ts index 8d2c787ce8..fc366d0147 100644 --- a/fission/src/test/mirabuf/MirabufParser.test.ts +++ b/fission/src/test/mirabuf/MirabufParser.test.ts @@ -1,7 +1,8 @@ import { describe, expect, test } from "vitest" -import { mirabuf } from "@/proto/mirabuf" import MirabufCachingService, { MiraType } from "../../mirabuf/MirabufLoader.ts" import MirabufParser, { type RigidNodeReadOnly } from "../../mirabuf/MirabufParser.ts" +import type { mirabuf } from "@/proto/mirabuf" +import type { Matrix4 } from "three" describe("Mirabuf Parser Tests", () => { test("Generate Rigid Nodes (Dozer_v9.mira)", async () => { @@ -13,15 +14,12 @@ describe("Mirabuf Parser Tests", () => { const t = new MirabufParser(spikeMira!) const rn = [...t.rigidNodes.values()] - expect(filterNonPhysicsNodes(rn, spikeMira!).length).toBe(7) - - // Validate joints - const jointValidation = validateJoints(spikeMira!) - expect(jointValidation.isValid).toBe(true) - expect(jointValidation.jointCount).toBe(6) - expect(jointValidation.wheelJoints).toBe(6) - expect(jointValidation.allJoints).toContain(mirabuf.joint.JointMotion.REVOLUTE) // Wheels are revolute joints - expect(jointValidation.allJoints).not.toContain(mirabuf.joint.JointMotion.SLIDER) // Dozer has no slider joints + const physicsNodes = filterNonPhysicsNodes(rn, spikeMira!).length + expect(physicsNodes).toBe(7) + expect([...t.partTreeValues.values()].length).toBe(13) + expect([...t.partToNodeMap.values()].length).toBe(12) + expect(await hashTransforms(t.globalTransforms)).toMatchSnapshot() + expect(t.rootNode).toBe("12") }) /* @@ -39,21 +37,13 @@ describe("Mirabuf Parser Tests", () => { const t = new MirabufParser(spikeMira!) const rn = [...t.rigidNodes.values()] + const physicsNodes = filterNonPhysicsNodes(rn, spikeMira!) - expect(filterNonPhysicsNodes(rn, spikeMira!).length).toBe(9) - - // Validate joints - const jointValidation = validateJoints(spikeMira!) - expect(jointValidation.isValid).toBe(true) - expect(jointValidation.jointCount).toBe(8) - - // Validate joint type distribution - const revoluteJoints = jointValidation.allJoints.filter(j => j === mirabuf.joint.JointMotion.REVOLUTE) - const sliderJoints = jointValidation.allJoints.filter(j => j === mirabuf.joint.JointMotion.SLIDER) - - expect(revoluteJoints.length).toBe(6) // Should have 6 revolute joints (4 wheels + 2 additional) - expect(sliderJoints.length).toBe(2) // Should have 2 slider joints - expect(jointValidation.wheelJoints).toBe(4) // Should have 4 wheel joints + expect(physicsNodes.length).toBe(9) + expect([...t.partTreeValues.values()].length).toBe(12) + expect([...t.partToNodeMap.values()].length).toBe(11) + expect(await hashTransforms(t.globalTransforms)).toMatchSnapshot() + expect(t.rootNode).toBe("16") }) test("Generate Rigid Nodes (FRC Field 2018_v13.mira)", async () => { @@ -61,12 +51,25 @@ describe("Mirabuf Parser Tests", () => { "/api/mira/fields/FRC Field 2018_v13.mira", MiraType.FIELD ).then(x => MirabufCachingService.get(x!.hash)) + const t = new MirabufParser(field!) + const physicsNodes = filterNonPhysicsNodes([...t.rigidNodes.values()], field!) - expect(filterNonPhysicsNodes([...t.rigidNodes.values()], field!).length).toBe(34) + expect(physicsNodes.length).toBe(34) + expect([...t.partTreeValues.values()].length).toBe(982) + expect([...t.partToNodeMap.values()].length).toBe(981) + expect(await hashTransforms(t.globalTransforms)).toMatchSnapshot() + expect(t.rootNode).toBe("35merged") }) }) +async function hashTransforms(globalTransforms: Map): Promise { + return crypto.subtle.digest( + "SHA-1", + new Int16Array([...globalTransforms.values()].flatMap(mat => mat.toArray()).map(n => Math.round(n * 1000))) + ) +} + function filterNonPhysicsNodes(nodes: RigidNodeReadOnly[], mira: mirabuf.Assembly): RigidNodeReadOnly[] { return nodes.filter(x => { for (const part of x.parts) { @@ -80,116 +83,6 @@ function filterNonPhysicsNodes(nodes: RigidNodeReadOnly[], mira: mirabuf.Assembl }) } -interface JointValidationResult { - isValid: boolean - jointCount: number - allJoints: mirabuf.joint.JointMotion[] - wheelJoints: number - errors: string[] - warnings: string[] -} - -function validateJoints(assembly: mirabuf.Assembly): JointValidationResult { - const result: JointValidationResult = { - isValid: true, - jointCount: 0, - allJoints: [], - wheelJoints: 0, - errors: [], - warnings: [], - } - - const jointData = assembly.data?.joints - if (!jointData) { - result.errors.push("No joint data found in assembly") - result.isValid = false - return result - } - - // Validate joint definitions and instances - const jointDefinitions = jointData.jointDefinitions || {} - const jointInstances = jointData.jointInstances || {} - - // Count non-grounded joints - const nonGroundedJoints = Object.entries(jointInstances).filter(([key]) => key !== "grounded") - result.jointCount = nonGroundedJoints.length - - // Validate each joint - for (const [jointId, jointInstance] of nonGroundedJoints) { - try { - // Check if joint definition exists - const jointDef = jointDefinitions[jointInstance.jointReference!] - if (!jointDef) { - result.errors.push( - `Joint instance '${jointId}' references missing definition '${jointInstance.jointReference}'` - ) - result.isValid = false - continue - } - - // Get all joints - if (jointDef.jointMotionType !== null && jointDef.jointMotionType !== undefined) - result.allJoints.push(jointDef.jointMotionType) - - // Check for wheel joints - if ( - jointDef.userData?.data?.wheel === "true" || - (jointDef.jointMotionType === mirabuf.joint.JointMotion.REVOLUTE && - jointDef.userData?.data?.wheelType !== undefined) - ) { - result.wheelJoints++ - } - - // Validate joint motion type specific properties - switch (jointDef.jointMotionType) { - case mirabuf.joint.JointMotion.REVOLUTE: - if (!jointDef.rotational) { - result.errors.push(`Revolute joint '${jointId}' missing rotational definition`) - result.isValid = false - } - break - case mirabuf.joint.JointMotion.SLIDER: - if (!jointDef.prismatic) { - result.errors.push(`Slider joint '${jointId}' missing prismatic definition`) - result.isValid = false - } - break - case mirabuf.joint.JointMotion.BALL: - // Note: Ball joint properties are validated differently in the mirabuf format - if (!jointDef.custom) { - result.warnings.push(`Ball joint '${jointId}' may be missing ball-specific configuration`) - } - break - case mirabuf.joint.JointMotion.CUSTOM: - if (!jointDef.custom) { - result.errors.push(`Custom joint '${jointId}' missing custom definition`) - result.isValid = false - } - break - } - - // Validate joint has an origin - if (!jointDef.origin) { - result.warnings.push(`Joint '${jointId}' has no origin defined`) - } - } catch (error) { - result.errors.push(`Error validating joint '${jointId}': ${error}`) - result.isValid = false - } - } - - // Validate rigid groups if they exist - if (jointData.rigidGroups) { - for (const rigidGroup of jointData.rigidGroups) { - if (!rigidGroup.occurrences || rigidGroup.occurrences.length < 2) { - result.warnings.push(`Rigid group '${rigidGroup.name}' has fewer than 2 occurrences`) - } - } - } - - return result -} - // function printRigidNodeParts(nodes: RigidNodeReadOnly[], mira: mirabuf.Assembly) { // nodes.forEach(x => { // console.log(`[ ${x.name} ]:`); diff --git a/fission/src/test/mirabuf/__snapshots__/MirabufParser.test.ts.snap b/fission/src/test/mirabuf/__snapshots__/MirabufParser.test.ts.snap new file mode 100644 index 0000000000..bcbfc384ec --- /dev/null +++ b/fission/src/test/mirabuf/__snapshots__/MirabufParser.test.ts.snap @@ -0,0 +1,76 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Mirabuf Parser Tests > Generate Rigid Nodes (Dozer_v9.mira) 1`] = ` +ArrayBuffer [ + -58, + -101, + -32, + -101, + 92, + 42, + -22, + 108, + -77, + -90, + 109, + -121, + 89, + 84, + 126, + 112, + 6, + 119, + -56, + -86, +] +`; + +exports[`Mirabuf Parser Tests > Generate Rigid Nodes (FRC Field 2018_v13.mira) 1`] = ` +ArrayBuffer [ + 49, + 4, + -64, + -119, + 117, + 107, + -68, + 77, + 91, + 87, + -110, + 83, + -6, + -64, + -126, + 34, + -12, + -107, + -22, + -39, +] +`; + +exports[`Mirabuf Parser Tests > Generate Rigid Nodes (Multi-Joint Wheels) 1`] = ` +ArrayBuffer [ + 82, + -89, + 54, + -8, + 77, + -99, + -32, + 48, + -87, + -65, + 12, + 95, + 81, + 73, + 126, + 2, + -24, + 39, + -15, + 51, +] +`;