import test from 'node:test';
import assert from 'node:assert/strict';
const { parseIndex, searchIndex, resultsToHTML } = await import('../src/sphinx.js');
// A miniature docs.python.org: enough shape to exercise every lookup path
// (single-number terms, title boosts, stemmed words, object anchors) without
// a fixture file to drift out of date.
const INDEX = {
docnames: ['library/json', 'library/threading', 'tutorial/appendix'],
titles: [
'json - JSON encoder and decoder',
'threading - Thread-based parallelism',
'Appendix',
],
terms: { json: 0, thread: [1, 2], socket: [2] },
titleterms: { json: [0], thread: [1] },
objects: { json: [[0, 3, 1, '', 'dumps']] },
objnames: { 3: ['py', 'function', 'Python function'] },
};
const BASE = 'https://docs.python.org/3/';
test('parseIndex unwraps Search.setIndex() and refuses anything else', () => {
assert.equal(parseIndex('Search.setIndex({"a": 1})').a, 1);
assert.throws(() => parseIndex('a block page'), /not a Sphinx search index/);
assert.throws(() => parseIndex('Search.setIndex(undefined)'), /not a Sphinx search index/);
});
test('a title hit outranks body hits, and one-doc terms stored as a bare number work', () => {
const found = searchIndex(INDEX, 'thread');
assert.deepEqual(found.docs.map((d) => d.doc), [1, 2]);
assert.equal(searchIndex(INDEX, 'json').docs[0].doc, 0);
});
test('a word Sphinx stemmed away still matches through its stem', () => {
// The index stores 'thread'; a query typed as English says 'threading'.
const found = searchIndex(INDEX, 'threading');
assert.equal(found.docs[0].doc, 1);
});
test('titles are flattened to text before they reach the results page', () => {
const found = searchIndex(INDEX, 'json');
assert.equal(found.docs[0].title, 'json - JSON encoder and decoder');
});
test('a tag the title never closes is stripped, not left standing', () => {
// 'json encoder