import test from 'node:test'; import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import { runInNewContext } from 'node:vm'; import ts from 'typescript'; import { ConfigFetchError, ConfigParseError } from '../../YouleNexus/assets/framework/config/remote-config.ts'; // 在引擎资源边界验证错误、JSON 解析和缓存释放,不以 HTTP 模拟项目资源。 function fixture(debug: boolean, text: string, error?: Error, debugIO = false) { const calls: string[] = []; const logs: unknown[][] = []; const exports: any = {}; class TextAsset {} const resources = { load(path: string, type: unknown, done: Function) { assert.equal(type, TextAsset); calls.push(`load:${path}`); done(error, { text }); }, release(path: string, type: unknown) { assert.equal(type, TextAsset); calls.push(`release:${path}`); }, }; const source = readFileSync(new URL('../../YouleNexus/assets/scripts/platform-login/local-config-fetcher.ts', import.meta.url), 'utf8'); runInNewContext(ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }, }).outputText, { exports, console: {log: (...args:unknown[])=>logs.push(args)}, require(name: string) { if (name === 'cc') return { resources, TextAsset }; if (name === 'cc/env') return { DEBUG: debug }; if (name.endsWith('/profiles.ts')) return { STARTUP_CONFIG: { debugIO } }; if (name.endsWith('/remote-config.ts')) return { ConfigFetchError, ConfigParseError }; throw Error(`Unexpected import: ${name}`); } }); return { fetcher: new exports.CocosLocalConfigFetcher(), calls, logs }; } test('config logging emits the parsed object and is silent when disabled', async () => { for(const enabled of [false,true]){ const f=fixture(true,'{"showVisitor":1}',undefined,enabled); const data=await f.fetcher.fetch('dev-config/test'); assert.deepEqual(f.logs,enabled?[['[Config LOCAL]','dev-config/test.txt',data]]:[]); if(enabled)assert.equal(typeof f.logs[0][2],'object'); } }); test('project txt parses JSON and releases the asset after every load', async () => { const f = fixture(true, '{"showVisitor":1}'); assert.equal((await f.fetcher.fetch('dev-config/test')).showVisitor, 1); await f.fetcher.fetch('dev-config/test'); assert.deepEqual(f.calls, ['load:dev-config/test', 'release:dev-config/test', 'load:dev-config/test', 'release:dev-config/test']); }); test('release build never loads local txt; missing or malformed assets expose source errors', async () => { const release = fixture(false, '{}'); await assert.rejects(release.fetcher.fetch('dev-config/test'), ConfigFetchError); assert.deepEqual(release.calls, []); const missing = fixture(true, '', Error('not found')); await assert.rejects(missing.fetcher.fetch('dev-config/test'), /test.txt.*not found/); const malformed = fixture(true, 'not json'); await assert.rejects(malformed.fetcher.fetch('dev-config/test'), ConfigParseError); assert.deepEqual(malformed.calls, ['load:dev-config/test', 'release:dev-config/test']); });