tricu

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

io-utf8.test.mjs (2189B)


      1 import test from 'node:test';
      2 import assert from 'node:assert/strict';
      3 import {encodeUTF8,decodeUTF8} from '../dist/io-utf8.js';
      4 test('all Unicode scalars match independent platform encoding and strict decoding',()=>{
      5  const encoder=new TextEncoder();
      6  for(let start=0;start<=0x10ffff;start+=1024){
      7   const scalars=[];for(let n=start;n<Math.min(start+1024,0x110000);n++)if(n<0xd800||n>0xdfff)scalars.push(n);
      8   const text=String.fromCodePoint(...scalars),expected=[...encoder.encode(text)];
      9   assert.deepEqual(encodeUTF8(text),expected);assert.deepEqual(decodeUTF8(expected,true),{text,carry:[]});
     10  }
     11 });
     12 test('every valid multibyte scalar prefix yields only copied bounded carry, and fails when final',()=>{
     13  const encoder=new TextEncoder();
     14  for(let n=128;n<=0x10ffff;n++){
     15   if(n>=0xd800&&n<=0xdfff)continue;
     16   const bytes=[...encoder.encode(String.fromCodePoint(n))];
     17   for(let split=1;split<bytes.length;split++){
     18    const prefix=bytes.slice(0,split),out=decodeUTF8(prefix,false);
     19    assert.equal(out.text,'');assert.deepEqual(out.carry,prefix);assert.notEqual(out.carry,prefix);
     20   }
     21  }
     22  // Exhaustive prefixes above; explicit final/invalid-prefix controls below keep
     23  // exception creation out of the million-scalar loop.
     24  for(const bytes of [[0xc2],[0xe0,0xa0],[0xf4,0x8f,0xbf]])assert.throws(()=>decodeUTF8(bytes,true),/incomplete/);
     25 });
     26 test('invalid lead/continuation/overlong/surrogate/range prefixes fail before finality',()=>{
     27  for(const bytes of [[0x80],[0xc0],[0xc1],[0xf5],[0xff],[0xe0,0x9f],[0xed,0xa0],[0xf0,0x8f],[0xf4,0x90],[0xc2,0x41],[0xe2,0x82,0x41]])
     28   for(const final of [false,true])assert.throws(()=>decodeUTF8(bytes,final),/invalid UTF-8/);
     29  assert.throws(()=>decodeUTF8([65,0xff],false),/at byte 1$/);
     30 });
     31 test('BOM, NUL, combining scalars and line endings are unchanged; scalar/byte bounds are separate',()=>{
     32  const text='\ufeffa\0\r\nĪ»šŸ˜€e\u0301';assert.deepEqual(decodeUTF8(encodeUTF8(text),true),{text,carry:[]});
     33  assert.equal(encodeUTF8('šŸ˜€'.repeat(1024)).length,4096);
     34  assert.throws(()=>encodeUTF8('a'.repeat(1025)),/scalar/);assert.throws(()=>encodeUTF8('\ud800'),/scalar/);
     35  assert.throws(()=>decodeUTF8(Array(4097).fill(65),false),/byte/);
     36 });