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;`; 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/); });