Files
sunrise/tests/building-assets.test.ts

50 lines
3.0 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { readFileSync } from 'node:fs';
import { Mesh, MeshStandardMaterial } from 'three';
import { createBuildings } from '../src/scene/buildings.ts';
import { loadBuildingAssets, createBakedBuildings } from '../src/scene/buildingAssets.ts';
test('saved buildings load without GeoJSON and preserve geometry and lighting exactly', async (t) => {
const requested: string[] = [];
t.mock.method(globalThis, 'fetch', async (input: string) => {
requested.push(input);
const path = new URL(input, 'http://localhost').pathname;
return new Response(readFileSync(new URL(`../public${path}`, import.meta.url)));
});
const metadata = JSON.parse(readFileSync(new URL('../public/terrain/gwanaksan.json', import.meta.url), 'utf8'));
const bytes = readFileSync(new URL('../public/terrain/gwanaksan.f32', import.meta.url));
const terrain = { metadata, heights: new Float32Array(bytes.buffer, bytes.byteOffset, bytes.byteLength / 4) };
const data = JSON.parse(readFileSync(new URL('../public/buildings/gwacheon.geojson', import.meta.url), 'utf8'));
const saved = await loadBuildingAssets();
assert.equal(requested.length, 2);
assert.ok(requested.every(path => !path.includes('.geojson')));
const baked = createBakedBuildings(saved, metadata);
const original = createBuildings(data, terrain);
try {
assert.deepEqual(baked.counts, original.counts);
assert.deepEqual(baked.target, original.target);
assert.equal(baked.group.children.length, original.group.children.length);
for (const [i, child] of baked.group.children.entries()) {
const actual = child as Mesh, expected = original.group.children[i] as Mesh;
assert.equal(actual.name, expected.name);
for (const name of ['position', 'normal', 'buildingLightHeight']) {
assert.deepEqual(actual.geometry.getAttribute(name).array, expected.geometry.getAttribute(name).array);
}
assert.deepEqual(actual.geometry.index!.array, expected.geometry.index!.array);
expected.geometry.computeBoundingBox(); expected.geometry.computeBoundingSphere();
assert.deepEqual(actual.geometry.boundingBox, expected.geometry.boundingBox);
assert.deepEqual(actual.geometry.boundingSphere, expected.geometry.boundingSphere);
assert.equal((actual.material as MeshStandardMaterial).color.getHex(), (expected.material as MeshStandardMaterial).color.getHex());
}
assert.deepEqual(baked.spill.texture.image.data, original.spill.texture.image.data);
assert.deepEqual(baked.spill.bounds, original.spill.bounds);
for (const altitude of [-8, 0, 6, -8]) {
baked.update(altitude); original.update(altitude);
assert.equal(baked.spill.intensity.value, original.spill.intensity.value);
}
assert.throws(() => createBakedBuildings(saved, { ...metadata, observerSurfaceElevation: metadata.observerSurfaceElevation + 1 }), /지형/);
assert.throws(() => createBakedBuildings({ ...saved, buffer: saved.buffer.slice(4) }, metadata), /건물/);
} finally { baked.dispose(); original.dispose(); }
});