import {readFileSync} from 'node:fs'; import assert from 'node:assert/strict'; import {test} from 'node:test'; import ts from 'typescript'; const source=readFileSync(new URL('../src/lib/latency-marker.ts',import.meta.url),'utf8'); const code=ts.transpileModule(source,{compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2022}}).outputText; const exports={};new Function('exports',code)(exports); const {drawMarker,decodeMarker}=exports; function image(counter,w=320,h=240) { const pixels=new Uint8ClampedArray(w*h*4); const ctx={canvas:{width:w,height:h},fillStyle:'',fillRect(x,y,width,height){ const c=this.fillStyle.startsWith('rgb(')?this.fillStyle.slice(4,-1).split(',').map(Number): this.fillStyle==='#fff'?[255,255,255]:this.fillStyle==='#000'?[0,0,0]:[60,60,60]; for(let yy=Math.max(0,Math.ceil(y));yy{ for(const id of [0,1,2,3,63,127,1023,2047,2048,4094,4095,4096]) { assert.equal(decodeMarker(image(id),320,240)?.counter,id&4095); } }); test('camera rotation and reflection preserve the observed ID',()=>{ const original=image(1371),rotated=new Uint8ClampedArray(original.length),flipped=new Uint8ClampedArray(original.length); for(let y=0;y<240;y++)for(let x=0;x<320;x++){ rotated.set(original.subarray((y*320+x)*4,(y*320+x)*4+4),(x*240+239-y)*4); flipped.set(original.subarray((y*320+x)*4,(y*320+x)*4+4),(y*320+319-x)*4); } assert.equal(decodeMarker(rotated,240,320)?.counter,1371); assert.equal(decodeMarker(flipped,320,240)?.counter,1371); }); test('missing fiducials and ambiguous rolling transitions do not invent latency samples',()=>{ assert.equal(decodeMarker(new Uint8ClampedArray(320*240*4),320,240),null); const pixels=image(123); for(let y=90;y<152;y++)for(let x=44;x<276;x++)pixels.set([128,128,128,255],(y*320+x)*4); assert.equal(decodeMarker(pixels,320,240),null); }); test('washed screen primaries survive without mistaking a blue-tinted background',()=>{ const pixels=image(1371); for(let i=0;i