import test from 'node:test'; import assert from 'node:assert/strict'; import {literalQuery,highlightParts,renderHighlighted,displayExcerpt,matchExplanation} from '../src/match-display.ts'; const marked = (text,query) => highlightParts(text,literalQuery(query)).filter(part => part.matched).map(part => part.text); test('literal marks use whole words, identifiers, quoted phrases and filename separators', () => { assert.deepEqual(marked('Contract contractual subcontract CONTRACT.', 'contract'), ['Contract','CONTRACT']); assert.deepEqual(marked('E_SEARCH_071 E_SEARCH_0712', 'E_SEARCH_071'), ['E_SEARCH_071']); assert.deepEqual(marked('invoice_october.pdf', 'invoice october'), ['invoice','october']); assert.deepEqual(marked('Give end of contract notice. Contract end.', '"end of contract"'), ['end of contract','Contract','end']); assert.deepEqual(marked('Use C++ and literal a+b, not aab.', 'C++ a+b'), ['C++','a+b']); }); test('accent and case matching preserves original combining characters and surrogate offsets', () => { const source='🧾 Café Cafe\u0301 MÜNCHEN München. 𐐀cafe'; const parts=highlightParts(source,literalQuery('cafe munchen')); assert.equal(parts.map(part => part.text).join(''),source); assert.deepEqual(parts.filter(part => part.matched).map(part => part.text), ['Café','Cafe\u0301','MÜNCHEN','München']); assert.equal(parts[0].text, '🧾 '); }); test('common English/German stopwords and punctuation do not create noisy evidence', () => { assert.deepEqual(marked('The and für über supplier', 'the and für'), []); assert.deepEqual(marked('The and. Supplier.', 'the and.'), []); assert.deepEqual(marked('The supplier partnership may end.', 'cancel the supplier partnership'), ['supplier','partnership']); }); test('query snapshots and mark runs are bounded; later inputs cannot relabel older results', () => { let input='supplier'; const snapshot=literalQuery(input); input='garden'; assert.equal(snapshot.query,'supplier'); assert.deepEqual(highlightParts('supplier garden',snapshot).filter(part => part.matched).map(part => part.text),['supplier']); assert.equal(Object.isFrozen(snapshot.patterns),true); assert.ok(literalQuery('x'.repeat(9000)).query.length <= 4096); assert.ok(literalQuery(Array.from({length:100},(_,i)=>`term${i}`).join(' ')).patterns.length <= 64); assert.ok(marked('supplier '.repeat(1000),'supplier').length <= 256); }); test('list excerpts remain original text around the first literal hit and retain ellipsis', () => { const text='Intro '.repeat(200)+'supplier partnership notice '+ 'Closing '.repeat(200); const excerpt=displayExcerpt(text,literalQuery('supplier partnership')); assert.ok(excerpt.length <= 424); assert.ok(excerpt.startsWith('… ')); assert.ok(excerpt.endsWith(' …')); assert.ok(excerpt.includes('supplier partnership')); assert.ok(text.includes(excerpt.slice(2,-2))); }); test('bounded marks retain the earliest hit across terms instead of favoring longest-term repetition', () => { const source='short '+ 'longerterm '.repeat(400); const parts=highlightParts(source,literalQuery('short longerterm')); assert.equal(parts[0].text,'short'); assert.equal(parts[0].matched,true); assert.ok(parts.filter(part=>part.matched).length <= 256); assert.equal(parts.map(part=>part.text).join(''),source); }); test('markup and regex-looking queries create text nodes and marks, never parsed HTML', () => { const nodes=[]; const doc={createDocumentFragment:()=>({append:node=>nodes.push(node)}),createElement:tag=>({tag,dataset:{},textContent:''}),createTextNode:text=>({text})}; const target={ownerDocument:doc,replaceChildren:()=>{}}; const source=' supplier [a-z].'; renderHighlighted(target,source,literalQuery('supplier [a-z]')); assert.equal(nodes.map(node=>node.text ?? node.textContent).join(''),source); assert.ok(nodes.some(node=>node.tag==='mark' && node.textContent==='supplier')); assert.ok(nodes.every(node=>node.tag===undefined || node.tag==='mark')); }); test('optional reasons use real source routes and never claim semantic word confidence', () => { const text=matchExplanation({match_kind:'semantic',source:{kind:'page',number:2}}); assert.match(text.reason,/page 2/); assert.match(text.legend,/without the same words/); assert.equal(text.semanticPassage,true); assert.match(matchExplanation({match_kind:'semantic_audio',source:{kind:'timestamp_ms',number:13129}}).reason,/0:13.*not an exact spoken phrase/); const speech=matchExplanation({match_kind:'semantic_speech',source:{kind:'timestamp_ms',number:13129}}); assert.match(speech.reason,/0:13.*estimated token position/); assert.equal(speech.semanticPassage,true); assert.match(matchExplanation({match_kind:'semantic_video',source:{kind:'timestamp_ms',number:24167}}).reason,/frame.*0:24/); assert.match(matchExplanation({match_kind:'semantic_image'}).reason,/whole/); assert.match(matchExplanation({match_kind:'name_terms'}).reason,/filename, path or content/); assert.equal(matchExplanation({match_kind:'hybrid',source:{kind:'page',number:2}}).semanticPassage,false); assert.doesNotMatch(JSON.stringify(text),/confidence|percent|importance/); }); test('code passage reasons retain actual indexed source line', () => { assert.match(matchExplanation({match_kind:'semantic', source:{kind:'line',number:97}}).reason, /at line 97/); assert.match(matchExplanation({match_kind:'hybrid', source:{kind:'line',number:97}}).reason, /showing the passage at line 97/); }); import {baseMatchKind,partitionResults} from '../src/match-display.ts'; import {ResultSelection} from '../src/selection-state.ts'; test('related candidates remain retained but excluded from collapsed keyboard selection', () => { const weak={path:'mountain',match_kind:'semantic_image_related'}, strong={path:'supplier',match_kind:'semantic'}, exact={path:'name',match_kind:'exact_filename'}; const found=[weak,strong,exact]; assert.deepEqual(partitionResults(found),{primary:[strong,exact],related:[weak],visible:[strong,exact]}); assert.deepEqual(partitionResults(found,true).visible,[strong,exact,weak]); assert.deepEqual(found,[weak,strong,exact]); }); test('only related has no implicit Enter target; empty stays distinct', () => { const weak={path:'weak',match_kind:'semantic_related'}; const selection=new ResultSelection(); selection.begin('missing'); assert.equal(selection.resolve(partitionResults([weak]).visible.map(r=>r.path)),-1); assert.equal(selection.resolve(partitionResults([weak],true).visible.map(r=>r.path)),0); assert.deepEqual(partitionResults([]),{primary:[],related:[],visible:[]}); }); test('progressive primary results preserve user intent across related disclosure', () => { const a={path:'a',match_kind:'content'},b={path:'b',match_kind:'semantic_related'}; const selection=new ResultSelection(); selection.begin('query'); selection.resolve(partitionResults([a,b]).visible.map(r=>r.path)); selection.choose('b'); assert.equal(selection.resolve(partitionResults([a,b],true).visible.map(r=>r.path)),1); assert.equal(selection.resolve(partitionResults([a,b]).visible.map(r=>r.path)),0); assert.equal(selection.resolve(partitionResults([a,b],true).visible.map(r=>r.path)),1); }); test('related media and speech retain source routes and explain unverified similarity', () => { for(const kind of ['semantic','semantic_image','semantic_audio','semantic_video','semantic_speech']) { assert.equal(baseMatchKind(kind+'_related'),kind); const primary=matchExplanation({match_kind:kind,source:{kind:'timestamp_ms',number:1500}}); const related=matchExplanation({match_kind:kind+'_related',source:{kind:'timestamp_ms',number:1500}}); assert.equal(related.semanticPassage,primary.semanticPassage); assert.equal(related.legend,primary.legend); assert.ok(related.reason.includes('similarity alone does not verify')); assert.ok(related.reason.endsWith(primary.reason)); } });