tricu

A lazy functional language based on Tree Calculus
Log | Files | Refs | README | LICENSE

program-catalogue.test.mjs (3876B)


      1 import test from 'node:test';
      2 import assert from 'node:assert/strict';
      3 import {readFile} from 'node:fs/promises';
      4 import {selectorLibraries,libraryLabel,exampleGroup,exampleGroups} from '../dist/program-catalogue.js';
      5 import {packageIndex,packageReleases} from '../dist/packages.js';
      6 const read=name=>readFile(new URL('../'+name,import.meta.url),'utf8').then(JSON.parse);
      7 test('selector merges identical native interfaces while preserving publications',async()=>{
      8  const releases=packageIndex(await read('packages.json')),before=JSON.stringify(releases),shown=selectorLibraries(releases);
      9  assert.equal(new Set(shown.map(r=>r.manifest)).size,shown.length);
     10  assert.equal(JSON.stringify(releases),before);
     11  assert(shown.some(r=>r.name==='tricu-lib-native-math'));assert(!shown.some(r=>r.name==='tricu-math'));
     12  assert(shown.some(r=>r.name==='tricu-lib-packages-base'));assert(!shown.some(r=>r.name==='tricu-base'));
     13  assert(shown.some(r=>r.name==='tricu-compiler'));assert(shown.some(r=>r.name==='tricu-source-builder'));
     14  for(const name of new Set(releases.filter(r=>!r.demo).map(r=>r.name))){
     15   const latest=packageReleases(releases,name)[0];assert(shown.some(r=>r.manifest===latest.manifest),name);
     16  }
     17  assert(shown.every(r=>!libraryLabel(r.name).startsWith('tricu-')));
     18  assert(releases.some(r=>r.demo==='intro'),'Retired publications remain available');
     19 });
     20 test('beginner progression and reference are separated from practical demos',async()=>{
     21  const catalogue=await read('catalogue.json');
     22  assert.deepEqual(exampleGroups,['Basic Examples','Practical Examples','Language & Runtime Explorations']);
     23  assert.deepEqual(catalogue.filter(e=>exampleGroup(e)==='Basic Examples').map(e=>e.id),['names-values','arithmetic','functions','lists','transform-list','choices']);
     24  assert.equal(catalogue.filter(e=>exampleGroup(e)==='Language & Runtime Explorations')[0].id,'language-reference');
     25  assert.equal(catalogue[0].export,'greeting');assert.equal(catalogue[0].output,'string');
     26  for(const entry of catalogue.filter(e=>exampleGroup(e)==='Basic Examples')){
     27   assert.equal(entry.source,await readFile(new URL('../demos/'+entry.id+'.tri',import.meta.url),'utf8'));
     28   assert.match(entry.source,/-- Next:|Choose "Doing arithmetic"/);
     29   if(entry.id!=='names-values'){
     30    assert.doesNotMatch(entry.source,/Click or tap|compile after|dropdown|inspection card/);
     31    assert.doesNotMatch(entry.source,/^!import .* as /m);
     32   }
     33   assert.doesNotMatch(entry.source,/Evaluate|Choose .* in Definition|Add import supplies/);
     34  }
     35  assert.equal(Object.keys(catalogue.find(e=>e.id==='language-reference').presets).length,16);
     36 });
     37 
     38 test('example sources stay synchronized and omit retired evaluator controls',async()=>{
     39  const catalogue=await read('catalogue.json');
     40  for(const entry of catalogue.filter(e=>['Basic Examples','Practical Examples'].includes(exampleGroup(e)))){
     41   assert.equal(entry.source,await readFile(new URL('../demos/'+entry.id+'.tri',import.meta.url),'utf8'));
     42   assert.doesNotMatch(entry.source,/Evaluate|their presets|Select v1\/v2|Record fields/);
     43  }
     44  const html=await readFile(new URL('../index.html',import.meta.url),'utf8');
     45  const app=await readFile(new URL('../dist/app.js',import.meta.url),'utf8');
     46  assert(!html.includes('playground-intro'));assert(!app.includes('playground-intro'));
     47 });
     48 
     49 test('basic examples publish results as well as the functions they teach',async()=>{
     50  const catalogue=await read('catalogue.json');
     51  const results={
     52   'names-values':['greetAndAnswer'],
     53   'functions':['sixDoubled','nineDoubled','area'],
     54   'lists':['numbers','itemCount','total'],
     55   'transform-list':['numbers','doubled','total'],
     56   'choices':['emptyBasket','oneItem','fullBasket'],
     57  };
     58  for(const [id,names] of Object.entries(results)){
     59   const entry=catalogue.find(e=>e.id===id);
     60   for(const name of names)assert.deepEqual(entry.presets[name].arguments,[],id+': '+name);
     61  }
     62 });