TalkingBot/chat-engine/tests/markerStripper.test.js

88 lines
3.2 KiB
JavaScript

const { MARKER_REGEX, parseMarker, MAX_MARKER_LEN } = require('../src/citations/markers');
const { createMarkerStripper } = require('../src/citations/markerStripper');
function consume(chunks) {
const stripper = createMarkerStripper();
let text = '';
const markers = [];
let malformed = 0;
for (const chunk of chunks) {
const step = stripper.push(chunk);
text += step.text;
markers.push(...step.markers);
malformed += step.malformed;
}
const tail = stripper.flush();
text += tail.text;
markers.push(...tail.markers);
malformed += tail.malformed;
return { text, markers, malformed };
}
function splitRandom(value, random) {
const chunks = [];
let index = 0;
while (index < value.length) {
const size = 1 + Math.floor(random() * 5);
chunks.push(value.slice(index, index + size));
index += size;
}
return chunks;
}
describe('marker grammar', () => {
it('parses pages, ranges, and chapters', () => {
expect(parseMarker('[[p:47]]')).toEqual({ kind: 'page', page: 47, pageEnd: 47 });
expect(parseMarker('[[P: 47 - 49]]')).toEqual({ kind: 'page', page: 47, pageEnd: 49 });
expect(parseMarker('[[ch:3]]')).toEqual({ kind: 'chapter', chapterNo: 3 });
expect(parseMarker('[[p:abc]]')).toBeNull();
expect(MAX_MARKER_LEN).toBe(24);
expect('see [[p:47]][[ch:3]]'.match(MARKER_REGEX)).toHaveLength(2);
});
});
describe('marker stripper', () => {
it('keeps the same text and markers for any chunk split', () => {
const source = 'Start [[p:47]] middle [[p:47-49]][[ch:3]] end.';
const whole = consume([source]);
let seed = 7;
const random = () => {
seed = (seed * 1103515245 + 12345) % 2147483648;
return seed / 2147483648;
};
for (let trial = 0; trial < 30; trial += 1) {
expect(consume(splitRandom(source, random))).toEqual(whole);
}
expect(whole.text).toBe('Start middle end.');
expect(whole.markers).toEqual([
{ kind: 'page', page: 47, pageEnd: 47 },
{ kind: 'page', page: 47, pageEnd: 49 },
{ kind: 'chapter', chapterNo: 3 },
]);
});
it('handles markers at the start, middle, and end', () => {
expect(consume(['[[ch:3]] Hello']).text).toBe('Hello');
expect(consume(['Hello [[p:2]] there']).text).toBe('Hello there');
expect(consume(['Hello [[p:2]].']).text).toBe('Hello.');
});
it('rejoins markers split across chunks', () => {
expect(consume(['[[', 'p:', '47]]']).markers).toEqual([{ kind: 'page', page: 47, pageEnd: 47 }]);
expect(consume(['[', '[p:47]]']).text).toBe('');
expect(consume(['See [', '[p:1]] now']).text).toBe('See now');
});
it('strips malformed markers and keeps ordinary brackets', () => {
const bad = consume(['Note [[p:abc]] next']);
expect(bad.text).toBe('Note next');
expect(bad.markers).toEqual([]);
expect(bad.malformed).toBe(1);
expect(consume(['[[p:4']).text).toBe('[[p:4');
expect(consume(['Read [text](url) please']).text).toBe('Read [text](url) please');
expect(consume(['Just [[ here']).text).toBe('Just [[ here');
expect(consume(['[[ not a marker at all and much longer than the hold']).text).toContain('[[');
expect(consume(['Café [[p:8]] résumé']).text).toBe('Café résumé');
});
});