record.test.mjs (1803B)
1 import test from 'node:test'; 2 import assert from 'node:assert/strict'; 3 import {Graph} from '../dist/graph.js'; 4 import {list,text,natural,readRecord,outputType,view} from '../dist/codecs.js'; 5 test('portable scalar records decode names/types safely with bounded output',()=>{ 6 const g=new Graph(); 7 const field=(name,tag,value)=>list(g,[text(g,name),natural(g,BigInt(tag)),value]); 8 const record=fields=>list(g,fields); 9 const root=record([field('name',0,text(g,'λ雪🙂')),field('cents',1,natural(g,2499n)),field('accepted',2,g.stem(g.leaf)),field('__proto__',0,text(g,'ordinary key'))]); 10 const decoded=readRecord(g,root); 11 assert.equal(Object.getPrototypeOf(decoded),null);assert.equal(decoded.__proto__,'ordinary key'); 12 assert.equal(JSON.parse(JSON.stringify(decoded)).cents,2499);assert.equal(decoded.accepted,true); 13 assert.equal(outputType('record'),'record');assert.deepEqual(view(g,root,'record').value,decoded); 14 assert.throws(()=>readRecord(g,record([field('x',0,text(g,'a')),field('x',0,text(g,'b'))])),/unique/); 15 assert.throws(()=>readRecord(g,record([field('',0,text(g,'a'))])),/nonempty/); 16 assert.throws(()=>readRecord(g,record([field('x',3,g.leaf)])),/tag/); 17 assert.throws(()=>readRecord(g,record([field('x',1,natural(g,2n**53n))])),/safe integer/); 18 assert.throws(()=>readRecord(g,record([field('x',2,g.fork(g.leaf,g.leaf))])),/Boolean/); 19 assert.throws(()=>readRecord(g,record([list(g,[text(g,'x'),g.leaf])])),/name tag value/); 20 assert.throws(()=>readRecord(g,record([field('x',0,list(g,[natural(g,0xd800n)]))])),/scalar/); 21 assert.throws(()=>readRecord(g,record(Array.from({length:33},(_,i)=>field(String(i),0,g.leaf)))),/List decode limit/); 22 assert.throws(()=>readRecord(g,record(Array.from({length:5},(_,i)=>field(String(i),0,text(g,'a'.repeat(4096)))))),/output limit/); 23 });