Complete room UI and protocol integration, move game definitions and resources behind bundle entries, publish authoritative version XML, and document single-game builds. Include all current resource changes and experiment artifacts.
84 lines
5.5 KiB
JavaScript
84 lines
5.5 KiB
JavaScript
import {test} from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {fileURLToPath} from 'node:url';
|
|
import {loadRoomAssetInventory,loadRoomAssetDefinitions,validateRoomAssets,compressUuid,parseRoomAssetDefinitions} from '../../scripts/lib/room-assets.mjs';
|
|
|
|
const assetsDir=fileURLToPath(new URL('../../YouleNexus/assets/',import.meta.url));
|
|
const inventory=()=>loadRoomAssetInventory(assetsDir);
|
|
const definitions=loadRoomAssetDefinitions(fileURLToPath(new URL('../../YouleNexus/assets/games',import.meta.url)));
|
|
const template=definitions.find(definition=>definition.key==='Game_Surface_3');
|
|
const erqiwang=definitions.find(definition=>definition.key==='erqiwang');
|
|
const original=inventory();
|
|
const copy=()=>structuredClone(original);
|
|
const erqiwangPath=erqiwang.resources.createRoom;
|
|
const uuidOf=name=>original.scripts.find(script=>script.name===name).uuid;
|
|
|
|
test('static definition extraction reads the authoritative object without executing game factories',()=>{
|
|
const declarations=Object.fromEntries(definitions.map(definition=>[definition.key,definition]));
|
|
const text=`throw Error('must never execute'); export const GAME_DEFINITIONS=${JSON.stringify(declarations)} as const satisfies Record<string, GameDefinition>;`;
|
|
assert.deepEqual(parseRoomAssetDefinitions(text),definitions);
|
|
assert.throws(()=>parseRoomAssetDefinitions(text.replace('"key":"erqiwang"','"key":"another-game"')),/registration erqiwang differs/);
|
|
assert.throws(()=>parseRoomAssetDefinitions(text.replace('"createPageClass":"ErqiwangCreateRoomView"','"createPageClass":getClassName()')),/createPageClass must be a nonempty string literal/);
|
|
});
|
|
|
|
test('script UUID compression agrees with an actual serialized component and inherited page metadata',()=>{
|
|
const script=original.scripts.find(script=>script.name==='ErqiwangCreateRoomView');
|
|
assert.ok(script.contracts.includes('CreateRoomPage'));
|
|
assert.ok(original.assets.find(asset=>asset.path===erqiwangPath).objects.some(object=>object.__type__===compressUuid(script.uuid)));
|
|
});
|
|
test('current template and erqiwang assets have unique pages and matching composition references',()=>{
|
|
assert.deepEqual(validateRoomAssets(original,definitions),[]);
|
|
});
|
|
test('duplicate template component on erqiwang prefab is rejected',()=>{
|
|
const data=copy();
|
|
const prefab=data.assets.find(asset=>asset.path===erqiwangPath);
|
|
prefab.objects.push({__type__:compressUuid(uuidOf('TemplateCreateRoomView')),node:{__id__:1}});
|
|
assert.match(validateRoomAssets(data,definitions).join('\n'),/exactly one CreateRoomPage.*found 2/);
|
|
});
|
|
test('wrong game page and missing page are rejected',()=>{
|
|
const data=copy();
|
|
const page=data.assets.find(asset=>asset.path===erqiwangPath).objects.find(object=>object.__type__===compressUuid(uuidOf('ErqiwangCreateRoomView')));
|
|
page.__type__=compressUuid(uuidOf('TemplateCreateRoomView'));
|
|
assert.match(validateRoomAssets(data,definitions).join('\n'),/expected ErqiwangCreateRoomView.*TemplateCreateRoomView/);
|
|
page.__type__='cc.Component';
|
|
assert.match(validateRoomAssets(data,definitions).join('\n'),/exactly one CreateRoomPage.*found 0/);
|
|
});
|
|
test('serialized composition cannot retain private prefab references',()=>{
|
|
const data=copy();
|
|
const composition=data.assets.flatMap(asset=>asset.objects).find(object=>object.gameKey==='erqiwang');
|
|
composition.createRoom={__uuid__:data.assets.find(asset=>asset.path===template.resources.createRoom).uuid};
|
|
assert.match(validateRoomAssets(data,definitions).join('\n'),/createRoom.*must not be a serialized/);
|
|
composition.room={__uuid__:'00000000-0000-0000-0000-000000000000'};
|
|
assert.match(validateRoomAssets(data,definitions).join('\n'),/room.*must not be a serialized/);
|
|
});
|
|
test('unknown configured game, unresolved script and duplicate room views are rejected',()=>{
|
|
const data=copy();
|
|
const composition=data.assets.flatMap(asset=>asset.objects).find(object=>object.gameKey==='erqiwang');
|
|
composition.gameKey='missing-game';
|
|
const room=data.assets.find(asset=>asset.path===erqiwang.resources.room);
|
|
room.objects.push({__type__:compressUuid(uuidOf('TemplateRoomView')),node:{__id__:1}});
|
|
data.assets.find(asset=>asset.path===erqiwangPath).objects.push({__type__:compressUuid('00000000-0000-0000-0000-000000000001'),node:{__id__:1}});
|
|
const errors=validateRoomAssets(data,definitions).join('\n');
|
|
assert.match(errors,/unknown game missing-game/);
|
|
assert.match(errors,/unresolved script/);
|
|
assert.match(errors,/exactly one room view.*found 2/);
|
|
});
|
|
|
|
test('inheritance resolves the erqiwang room view through its shared public base',()=>{
|
|
const script=original.scripts.find(script=>script.name==='ErqiwangRoomView');
|
|
assert.ok(script.contracts.includes('CommonRoomViewBase'));
|
|
});
|
|
test('component on a child node cannot satisfy the platform root lookup',()=>{
|
|
const data=copy();
|
|
const page=data.assets.find(asset=>asset.path===erqiwangPath).objects.find(object=>object.__type__===compressUuid(uuidOf('ErqiwangCreateRoomView')));
|
|
page.node={__id__:2};
|
|
assert.match(validateRoomAssets(data,definitions).join('\n'),/must be attached to prefab root/);
|
|
});
|
|
test('an orphan component record cannot satisfy the platform root lookup',()=>{
|
|
const data=copy();
|
|
const prefab=data.assets.find(asset=>asset.path===erqiwangPath);
|
|
const pageIndex=prefab.objects.findIndex(object=>object.__type__===compressUuid(uuidOf('ErqiwangCreateRoomView')));
|
|
prefab.objects[prefab.objects[0].data.__id__]._components=prefab.objects[prefab.objects[0].data.__id__]._components.filter(reference=>reference.__id__!==pageIndex);
|
|
assert.match(validateRoomAssets(data,definitions).join('\n'),/not attached in the root component list/);
|
|
});
|