Files
Endoleap/tests/headless/json-data.test.mjs

20 lines
1.7 KiB
JavaScript

/**
* JSON隔离函数的语义与所有权测试。以日期、toJSON、稀疏数组、特殊键及循环等输入核对JSON转换与深冻结。
* 所有权证明只认可函数自己产生的结果,不能因调用方freeze或clone就复用内部证明。
*/
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {detachJsonData,hasDetachedJsonData} from '../../src/lib/canvas-core/json-data.ts';
// 修改外部嵌套对象/日期不得影响结果;数组空洞等变null,特殊键保留,伪造冻结副本无证明,循环/BigInt明确抛错。
test('JSON detachment owns only its copied immutable result and preserves JSON semantics',()=>{
let calls=0;const external={nested:{text:'before'},date:new Date('2026-01-01Z'),custom:{toJSON(){calls++;return{value:2};}},array:[,undefined,NaN],['__proto__']:{safe:true}};
const value=detachJsonData(external);assert.equal(calls,1);assert.equal(hasDetachedJsonData(value),true);assert.equal(hasDetachedJsonData(external),false);
external.nested.text='after';external.date.setUTCFullYear(2027);
assert.equal(value.nested.text,'before');assert.equal(value.date,'2026-01-01T00:00:00.000Z');assert.deepEqual(value.array,[null,null,null]);assert.equal(Object.hasOwn(value,'__proto__'),true);
assert.ok(Object.isFrozen(value.nested));assert.throws(()=>{value.nested.text='mutate';},TypeError);
assert.equal(hasDetachedJsonData(Object.freeze({...value})),false);assert.equal(hasDetachedJsonData(structuredClone(value)),false);
assert.equal(hasDetachedJsonData(Object.freeze({nested:{mutable:true}})),false);
const cycle={};cycle.self=cycle;assert.throws(()=>detachJsonData(cycle));assert.throws(()=>detachJsonData({big:1n}));
});