Files
Currency-War-SR/tools/gridfight-extract-node/level.test.mjs
T
2026-10-30 23:54:07 +07:00

71 lines
4.2 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import {Codec, asset_hash} from './stages.mjs';
import {references, candidates, locate, decodeRecord, ROOT_TYPES} from './level.mjs';
import {sha256} from './extract.mjs';
test('level references deduplicate paths while retaining JSON pointer citations', () => {
const p = 'Config/Level/GridFight/PortalBuff/GridFightPortal149.json';
assert.deepEqual(references({'a.json': {'a/b': [p, p], other: 'other.json'}}), [
{path: p, sources: [{file: 'a.json', pointer: '/a~1b/0'}, {file: 'a.json', pointer: '/a~1b/1'}]}
]);
assert.throws(() => candidates('Config/Level/GridFight/../secret.json'), /Invalid/);
});
test('level lookup distinguishes missing assets from corrupt indexed assets', () => {
const path = 'Config/Level/GridFight/SpotLight/GridFightSpotLight100000.json';
const missing = locate({layers: [new Map()], get() { assert.fail('missing index must not read'); }}, path);
assert.equal(missing.status, 'not-in-designv');
assert.equal(missing.attempts.length, 5);
const asset = 'BakedConfig/' + path.replace('.json', '.bytes');
const present = {layers: [new Map([[asset_hash(asset), {}]])], get(p) { assert.equal(p, asset); throw Error('Truncated indexed asset'); }};
assert.throws(() => locate(present, path), /Truncated/);
present.get = () => [Buffer.from([1]), {asset}];
assert.equal(locate(present, path).proof.asset, asset);
});
test('whole-record proof rejects trailing bytes, changed encoders, and stripped readers', () => {
const codec = new Codec(), type = 'RPG.GameCore.TestLevel';
codec.schemas[type] = [{name: 'Nodes', type: 'int[]'}, {name: 'Count', type: 'int'}];
codec.fields = () => new Map([[16, ['Nodes', 'int[]']], [24, ['Count', 'int']]]);
const row = {Nodes: [1, 6, -1], Count: 3}, raw = codec.encode_record(row, type);
assert.deepEqual(decodeRecord(codec, raw, type).row, row);
assert.throws(() => decodeRecord(codec, Buffer.concat([raw, Buffer.from([0])]), type), /round-trip/);
codec.encode_record = () => Buffer.from([0]);
assert.throws(() => decodeRecord(codec, raw, type), /round-trip/);
codec.fields = () => new Map();
assert.throws(() => decodeRecord(codec, Buffer.from([0]), type), /No serialized client fields/);
});
test('installed level audit exposes unknown rules without false round-trip proofs', () => {
const dir = new URL('../../resources/grid_fight/', import.meta.url);
const read = name => fs.readFileSync(new URL(name, dir));
const data = JSON.parse(read('level-availability.json')), proof = JSON.parse(read('level-provenance.json'));
const schemaFile = JSON.parse(read('level-schemas.json')), schemas = schemaFile.client_roots;
assert.equal(data.status, 'blocked-no-decoded-rule-assets');
assert.deepEqual(data.decoded_rule_assets, []);
assert.deepEqual(Object.values(data.rules), [null, null, null]);
assert.equal(data.assets.length, 914);
assert.ok(data.assets.every(a => a.status === 'not-in-designv' && a.attempts.length === 5));
assert.deepEqual(data.manifest_gridfight_level_paths, []);
assert.equal(proof.rule_asset_round_trips, 0);
const links = JSON.parse(read('level-links.raw.json')).GridFightSpecialGoodsConfigRow;
assert.equal(links.length, 164);
assert.ok(proof.tables.length > 0 && proof.tables.every(t => t.round_trip));
assert.equal(proof.tables.reduce((n, t) => n + t.records, 0), links.length);
assert.ok(schemaFile.tables['RPG.GameCore.GridFightSpecialGoodsConfigRow'].some(f => f.name === 'JsonPath'));
for (const row of links) assert.ok(data.assets.some(a => a.path === row.JsonPath));
assert.equal(proof.dump_sha256, JSON.parse(read('bonus-provenance.json')).dump_sha256);
for (const [name, hash] of Object.entries(proof.outputs)) assert.equal(sha256(read(name)), hash);
for (const name of ROOT_TYPES) {
const shape = schemas['RPG.GameCore.' + name];
assert.deepEqual(shape.fields, []);
assert.equal(shape.status, 'no-serialized-client-fields');
}
for (const name of ['GridFightActionTriggerSpotLightSelectConfig', 'GridFightModifierEliteBranchExtraRewardConfig']) {
assert.ok(schemas['RPG.GameCore.' + name].methods.some(m => m.immediate_ret));
}
assert.ok(!JSON.stringify(proof).includes('/home/'));
});