'use strict'; /** * Self-test for keywords.js — the parsing and matching rules, pinned. * * node modules/overflow-tap/keywords.selftest.js */ const assert = require('node:assert/strict'); const { parseKeywordLines, keywordMatches, matchKeyword, cleanNotes } = require('./keywords'); let n = 0; function test(name, fn) { n += 1; try { fn(); console.log(`ok ${name}`); } catch (err) { console.log(`FAIL ${name}\n ${err.message}`); process.exitCode = 1; } } test('parses keyword = destination, with -> and → too', () => { const m = parseKeywordLines('give = Give Online\nconnect -> Connect Card\nprayer → Prayer Request'); assert.deepEqual(m.map((x) => [x.keyword, x.destination, x.problem]), [ ['give', 'Give Online', ''], ['connect', 'Connect Card', ''], ['prayer', 'Prayer Request', ''], ]); }); test('a trailing @ names the groups for that line', () => { const [m] = parseKeywordLines('connect = Connect Card @ Lobby, Kids Wing'); assert.equal(m.destination, 'Connect Card'); assert.deepEqual(m.groups, ['Lobby', 'Kids Wing']); }); test('blank lines and # comments are skipped, line numbers kept', () => { const m = parseKeywordLines('\n# giving\n\ngive = Give Online\n'); assert.equal(m.length, 1); assert.equal(m[0].line, 4); }); test('a line without a separator is a problem, not a crash', () => { const [m] = parseKeywordLines('give'); assert.equal(m.keyword, 'give'); assert.match(m.problem, /No destination/); }); test('missing keyword or destination is reported', () => { const [a, b] = parseKeywordLines('= Give Online\ngive ='); assert.match(a.problem, /No keyword/); assert.match(b.problem, /No destination/); }); test('a repeated keyword is flagged and the first line wins', () => { const m = parseKeywordLines('give = A\nGIVE = B'); assert.equal(m[0].problem, ''); assert.match(m[1].problem, /Repeated/); assert.equal(matchKeyword('give', m).destination, 'A'); }); test('keywords and destinations may be phrases', () => { const [m] = parseKeywordLines('next steps = Next Steps Card'); assert.equal(m.keyword, 'next steps'); assert.equal(keywordMatches('Please fill out your Next Steps card', 'next steps', 'word'), true); }); test('whole word: give does not fire on forgiveness, does on "give!"', () => { assert.equal(keywordMatches('a sermon on forgiveness', 'give', 'word'), false); assert.equal(keywordMatches('give!', 'give', 'word'), true); assert.equal(keywordMatches('Give', 'give', 'word'), true); assert.equal(keywordMatches('#give now', 'give', 'word'), true); assert.equal(keywordMatches('giveaway', 'give', 'word'), false); assert.equal(keywordMatches('give_now', 'give', 'word'), false); }); test('anywhere: plain substring, like the Overflow helper', () => { assert.equal(keywordMatches('a sermon on forgiveness', 'give', 'anywhere'), true); assert.equal(keywordMatches('nothing here', 'give', 'anywhere'), false); }); test('line: the keyword on its own line only', () => { assert.equal(keywordMatches('speaker note\ngive\nmore', 'give', 'line'), true); assert.equal(keywordMatches('give now', 'give', 'line'), false); assert.equal(keywordMatches(' Give ', 'give', 'line'), true); }); test('regex characters in a keyword are literal', () => { assert.equal(keywordMatches('go to (give) now', '(give)', 'word'), true); assert.equal(keywordMatches('give.now', 'give.now', 'anywhere'), true); assert.equal(keywordMatches('giveXnow', 'give.now', 'anywhere'), false); }); test('empty notes never match; zero-width padding is ignored', () => { assert.equal(keywordMatches('', 'give'), false); assert.equal(keywordMatches('​', 'give', 'anywhere'), false); assert.equal(cleanNotes('​give'), 'give'); assert.equal(keywordMatches('​give', 'give', 'line'), true); }); test('matchKeyword returns the first mapping in admin order', () => { const m = parseKeywordLines('connect = Connect Card\ngive = Give Online'); assert.equal(matchKeyword('give and connect', m).keyword, 'connect'); assert.equal(matchKeyword('just worship', m), null); assert.equal(matchKeyword('give', []), null); }); test('a mapping with a parse problem can still be the match (the caller decides)', () => { const m = parseKeywordLines('baptism'); assert.equal(matchKeyword('baptism', m).problem.length > 0, true); }); console.log(`${n} tests, exit ${process.exitCode || 0}`);