/** * 浏览器摘要适配器的协议故障测试:使用可控 Worker 替身检查请求/响应身份,以及启动和运行失败的错误区分。 * 不启动真实线程,也不验证浏览器打包;每个用例恢复 globalThis.Worker,避免污染其他测试。 */ import {test} from 'node:test'; import assert from 'node:assert/strict'; import {createBrowserDigests} from '../../src/lib/canvas-runtime/browser-digests.ts'; // Worker 回传错误 id 即使摘要格式正确也必须拒绝;故障 worker 需 terminate,不能把别的任务结果交给当前调用者。 test('browser digest adapter rejects mismatched worker identity and terminates the worker',async()=>{ const previous=globalThis.Worker;let terminated=0; globalThis.Worker=class{/* 模拟线程稍后回信,故意把 id 加一;其余字段合法以隔离身份校验。 */ postMessage(value){queueMicrotask(()=>this.onmessage({data:{version:1,id:value.id+1,byteLength:value.bytes.size,sha256:'a'.repeat(64)}}));}/* 计数故障后的终止动作。 */ terminate(){terminated++;}}; const pool=createBrowserDigests();try{await assert.rejects(pool.digest(new Blob(['bytes'])),/invalid_digest_response/);assert.equal(terminated,1);}finally{pool.close();if(previous===undefined)delete globalThis.Worker;else globalThis.Worker=previous;} }); // 构造器抛错映射为 worker_unavailable,onerror 映射为 worker_failed;两个路径都不能给调用者返回伪造摘要。 test('browser digest adapter exposes worker startup and runtime failures without returning a false hash',async()=>{ const previous=globalThis.Worker;let pool; try{globalThis.Worker=class{/* 在线程创建阶段抛错,尚未进入 postMessage。 */ constructor(){throw Error('denied');}};pool=createBrowserDigests();await assert.rejects(pool.digest(new Blob()),/digest_worker_unavailable/);pool.close();let terminated=0;globalThis.Worker=class{/* 在线程运行阶段触发 onerror,区别于构造失败。 */ postMessage(){queueMicrotask(()=>this.onerror({preventDefault(){}}));}/* 计数故障后的终止动作。 */ terminate(){terminated++;}};pool=createBrowserDigests();await assert.rejects(pool.digest(new Blob()),/digest_worker_failed/);assert.equal(terminated,1);}finally{pool?.close();if(previous===undefined)delete globalThis.Worker;else globalThis.Worker=previous;} });