auto-git:
[add] tests/domain/foliage.test.ts
This commit is contained in:
169
tests/domain/foliage.test.ts
Normal file
169
tests/domain/foliage.test.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
createProjectAssetStorageKey,
|
||||
type ModelAssetRecord
|
||||
} from "../../src/assets/project-assets";
|
||||
import {
|
||||
createEmptySceneDocument,
|
||||
createSceneDocumentFromProject,
|
||||
createEmptyProjectDocument
|
||||
} from "../../src/document/scene-document";
|
||||
import { validateSceneDocument } from "../../src/document/scene-document-validation";
|
||||
import { BUNDLED_FOLIAGE_PROTOTYPES } from "../../src/foliage/bundled-foliage-manifest";
|
||||
import {
|
||||
FOLIAGE_PROTOTYPE_LOD_LEVELS,
|
||||
createFoliageLayer,
|
||||
createFoliagePrototype,
|
||||
type FoliagePrototypeLod
|
||||
} from "../../src/foliage/foliage";
|
||||
|
||||
function createModelAsset(id: string): ModelAssetRecord {
|
||||
return {
|
||||
id,
|
||||
kind: "model",
|
||||
sourceName: `${id}.glb`,
|
||||
mimeType: "model/gltf-binary",
|
||||
storageKey: createProjectAssetStorageKey(id),
|
||||
byteLength: 1024,
|
||||
metadata: {
|
||||
kind: "model",
|
||||
format: "glb",
|
||||
sceneName: null,
|
||||
nodeCount: 1,
|
||||
meshCount: 1,
|
||||
materialNames: [],
|
||||
textureNames: [],
|
||||
animationNames: [],
|
||||
boundingBox: null,
|
||||
warnings: []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createProjectAssetLods(modelAssetId: string): FoliagePrototypeLod[] {
|
||||
return FOLIAGE_PROTOTYPE_LOD_LEVELS.map((level) => ({
|
||||
level,
|
||||
source: "projectAsset",
|
||||
modelAssetId,
|
||||
maxDistance: 20 + level * 20,
|
||||
castShadow: level < 2
|
||||
}));
|
||||
}
|
||||
|
||||
describe("foliage document foundations", () => {
|
||||
it("accepts scene foliage layers that reference bundled prototype ids", () => {
|
||||
const bundledPrototype = BUNDLED_FOLIAGE_PROTOTYPES[0];
|
||||
const document = createEmptySceneDocument();
|
||||
const layer = createFoliageLayer({
|
||||
id: "foliage-layer-meadow",
|
||||
name: "Meadow",
|
||||
prototypeIds: [bundledPrototype.id]
|
||||
});
|
||||
|
||||
document.foliageLayers[layer.id] = layer;
|
||||
|
||||
expect(validateSceneDocument(document).errors).toEqual([]);
|
||||
});
|
||||
|
||||
it("accepts custom project-asset sourced foliage prototypes", () => {
|
||||
const modelAsset = createModelAsset("asset-custom-foliage");
|
||||
const document = createEmptySceneDocument();
|
||||
const prototype = createFoliagePrototype({
|
||||
id: "foliage-custom-clover",
|
||||
label: "Custom Clover",
|
||||
category: "grass",
|
||||
lods: createProjectAssetLods(modelAsset.id)
|
||||
});
|
||||
const layer = createFoliageLayer({
|
||||
id: "foliage-layer-custom",
|
||||
name: "Custom Foliage",
|
||||
prototypeIds: [prototype.id]
|
||||
});
|
||||
|
||||
document.assets[modelAsset.id] = modelAsset;
|
||||
document.foliagePrototypes[prototype.id] = prototype;
|
||||
document.foliageLayers[layer.id] = layer;
|
||||
|
||||
expect(validateSceneDocument(document).errors).toEqual([]);
|
||||
});
|
||||
|
||||
it("validates layer ranges and prototype references", () => {
|
||||
const document = createEmptySceneDocument();
|
||||
const layer = createFoliageLayer({
|
||||
id: "foliage-layer-invalid",
|
||||
name: "Invalid",
|
||||
prototypeIds: ["missing-foliage-prototype"]
|
||||
});
|
||||
|
||||
document.foliageLayers[layer.id] = {
|
||||
...layer,
|
||||
minScale: 2,
|
||||
maxScale: 1,
|
||||
maxSlopeDegrees: 120,
|
||||
noiseStrength: 1.5
|
||||
};
|
||||
|
||||
expect(validateSceneDocument(document).errors).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ code: "invalid-foliage-layer-scale-range" }),
|
||||
expect.objectContaining({ code: "invalid-foliage-layer-max-slope" }),
|
||||
expect.objectContaining({
|
||||
code: "invalid-foliage-layer-noise-strength"
|
||||
}),
|
||||
expect.objectContaining({ code: "missing-foliage-layer-prototype" })
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("validates custom project-asset LOD references", () => {
|
||||
const document = createEmptySceneDocument();
|
||||
const prototype = createFoliagePrototype({
|
||||
id: "foliage-missing-model",
|
||||
label: "Missing Model",
|
||||
category: "other",
|
||||
lods: createProjectAssetLods("asset-missing")
|
||||
});
|
||||
|
||||
document.foliagePrototypes[prototype.id] = prototype;
|
||||
|
||||
expect(validateSceneDocument(document).errors).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
code: "missing-foliage-prototype-model-asset"
|
||||
})
|
||||
])
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps project custom prototypes global and layers scene-local", () => {
|
||||
const modelAsset = createModelAsset("asset-project-foliage");
|
||||
const project = createEmptyProjectDocument({
|
||||
assets: {
|
||||
[modelAsset.id]: modelAsset
|
||||
}
|
||||
});
|
||||
const prototype = createFoliagePrototype({
|
||||
id: "foliage-project-reed",
|
||||
label: "Project Reed",
|
||||
category: "grass",
|
||||
lods: createProjectAssetLods(modelAsset.id)
|
||||
});
|
||||
const layer = createFoliageLayer({
|
||||
id: "foliage-layer-project-reed",
|
||||
name: "Project Reed Layer",
|
||||
prototypeIds: [prototype.id]
|
||||
});
|
||||
|
||||
project.foliagePrototypes[prototype.id] = prototype;
|
||||
project.scenes[project.activeSceneId]!.foliageLayers[layer.id] = layer;
|
||||
|
||||
const sceneDocument = createSceneDocumentFromProject(project);
|
||||
|
||||
expect(sceneDocument.foliagePrototypes).toEqual(project.foliagePrototypes);
|
||||
expect(sceneDocument.foliageLayers).toEqual(
|
||||
project.scenes[project.activeSceneId]!.foliageLayers
|
||||
);
|
||||
expect(validateSceneDocument(sceneDocument).errors).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user