tricu

An interpreted language for exploring Tree Calculus
Log | Files | Refs | README | LICENSE

compiler-package.test.mjs (2978B)


      1 import test from 'node:test';
      2 import assert from 'node:assert/strict';
      3 import {readFile} from 'node:fs/promises';
      4 import {compilerDescriptor,COMPILER_EXPORT} from '../dist/compiler.js';
      5 import {BUNDLE_LIMIT} from '../dist/bundle.js';
      6 const descriptor=JSON.parse(await readFile(new URL('../compiler.json',import.meta.url)));
      7 const bytes=await readFile(new URL('../bundles/'+descriptor.hash+'.arboricx',import.meta.url));
      8 let instance=0;
      9 async function session(message,fetcher,after){
     10  const saved={fetch:globalThis.fetch,onmessage:globalThis.onmessage,postMessage:globalThis.postMessage};
     11  let timer;
     12  try{
     13   globalThis.fetch=fetcher;
     14   const messages=[];
     15   const reply=new Promise((resolve,reject)=>{
     16    timer=setTimeout(()=>reject(Error('worker test timeout')),5000);
     17    globalThis.postMessage=data=>{messages.push(data);if(data.type==='loaded'||data.type==='error')resolve(data);};
     18   });
     19   await import('../dist/conformance/worker.js?test='+ ++instance);
     20   globalThis.onmessage({data:message});
     21   const result=await reply;
     22   if(after)await after(result,messages);
     23   return result;
     24  }finally{
     25   clearTimeout(timer);
     26   for(const [key,value] of Object.entries(saved))if(value===undefined)delete globalThis[key];else globalThis[key]=value;
     27  }
     28 }
     29 
     30 test('stable compiler descriptors reject arrays, wrong backends/entrypoints and malformed pins',()=>{
     31  assert.equal(compilerDescriptor(descriptor).hash,descriptor.hash);
     32  for(const raw of [null,[],{...descriptor,schema:2},{...descriptor,backend:'experimental'},{...descriptor,export:'main'},{...descriptor,hash:'A'.repeat(64)}])assert.throws(()=>compilerDescriptor(raw));
     33 });
     34 
     35 test('the indexed compiler loads and downloads exact bytes as an ordinary package without compiling',async()=>{
     36  const requests=[];
     37  const fetcher=async url=>{requests.push(String(url));return new Response(bytes);};
     38  const loaded=await session({type:'load',hash:descriptor.hash},fetcher,async(result,messages)=>{
     39   assert.equal(result.type,'loaded');assert.ok(result.exports.some(e=>e.name===COMPILER_EXPORT));
     40   assert.equal(result.source,null);assert.ok(result.nodes<=100000);
     41   globalThis.onmessage({data:{type:'download'}});
     42   const download=messages.at(-1);assert.equal(download.type,'downloaded');assert.equal(download.hash,descriptor.hash);
     43   assert.deepEqual(Buffer.from(download.bytes),bytes);
     44   assert.equal(messages.some(m=>m.type==='done'),false,'load/download never execute a program');
     45  });
     46  assert.equal(loaded.type,'loaded');assert.equal(requests.length,1);
     47  assert.equal(requests.some(url=>url.endsWith('/compiler.json')),false);
     48 });
     49 
     50 test('ordinary packages retain their byte ceiling and SHA-256 verification',async()=>{
     51  const wrong=await session({type:'load',hash:'0'.repeat(64)},async()=>new Response(bytes));
     52  assert.match(wrong.message,/SHA-256 mismatch/);
     53  const oversized=await session({type:'load',hash:descriptor.hash},async()=>new Response(new Uint8Array(BUNDLE_LIMIT+1)));
     54  assert.match(oversized.message,/download limit/);
     55 });