Files
cinny/src/app/utils/ASCIILexicalTable.test.ts
T

91 lines
3.1 KiB
TypeScript
Raw Normal View History

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { ASCIILexicalTable, orderKeys } from './ASCIILexicalTable';
const a = 'a'.charCodeAt(0);
const z = 'z'.charCodeAt(0);
const makeLex = (maxWidth = 4) => new ASCIILexicalTable(a, z, maxWidth);
const isStrictlyIncreasing = (keys: string[]): boolean =>
keys.every((key, i) => i === 0 || keys[i - 1] < key);
test('orderKeys returns an empty array for empty input', () => {
const lex = makeLex();
assert.deepEqual(orderKeys(lex, []), []);
});
test('orderKeys preserves all existing keys when none are missing', () => {
const lex = makeLex();
assert.deepEqual(orderKeys(lex, ['a', 'b', 'c']), ['a', 'b', 'c']);
});
test('orderKeys keeps existing keys and fills a single interior gap', () => {
const lex = makeLex();
const result = orderKeys(lex, ['b', undefined, 'd']);
assert.deepEqual(result, ['b', 'c', 'd']);
});
test('orderKeys output length always matches input length', () => {
const lex = makeLex();
const inputs: Array<Array<string | undefined>> = [
[undefined],
[undefined, undefined],
[undefined, undefined, undefined],
['b', undefined, undefined, 'y'],
];
inputs.forEach((input) => {
const result = orderKeys(lex, input);
assert.ok(result, 'expected a defined result');
assert.equal(result?.length, input.length);
});
});
test('orderKeys produces strictly increasing, valid keys', () => {
const lex = makeLex();
const result = orderKeys(lex, [undefined, undefined, undefined, undefined]);
assert.ok(result);
assert.equal(result?.length, 4);
assert.ok(isStrictlyIncreasing(result as string[]));
assert.ok((result as string[]).every((key) => lex.has(key)));
});
test('orderKeys keeps fixed keys at their positions when filling gaps', () => {
const lex = makeLex();
const result = orderKeys(lex, ['b', undefined, undefined, 'y']) as string[];
assert.equal(result[0], 'b');
assert.equal(result[3], 'y');
assert.ok(isStrictlyIncreasing(result));
});
test('orderKeys is deterministic for the same input', () => {
const lex = makeLex();
const first = orderKeys(lex, [undefined, undefined, undefined]);
const second = orderKeys(lex, [undefined, undefined, undefined]);
assert.deepEqual(first, second);
});
test('orderKeys handles a leading gap before an existing key', () => {
const lex = makeLex();
const result = orderKeys(lex, [undefined, 'm']) as string[];
assert.equal(result.length, 2);
assert.equal(result[1], 'm');
assert.ok(result[0] < 'm');
});
test('orderKeys handles a trailing gap after an existing key', () => {
const lex = makeLex();
const result = orderKeys(lex, ['m', undefined]) as string[];
assert.equal(result.length, 2);
assert.equal(result[0], 'm');
assert.ok(result[1] > 'm');
});
test('orderKeys works with a tiny table', () => {
const tiny = new ASCIILexicalTable('a'.charCodeAt(0), 'b'.charCodeAt(0), 2);
const result = orderKeys(tiny, [undefined, undefined]) as string[];
assert.equal(result.length, 2);
assert.ok(isStrictlyIncreasing(result));
assert.ok(result.every((key) => tiny.has(key)));
});