Update test_search.cjs

补充搜索排序、问法、同义词和中英文混写的测试。
This commit is contained in:
CyC2018
2026-11-01 20:08:24 +08:00
parent d8e8ba51c1
commit 08626a00ac
+40 -1
View File
@@ -1,7 +1,7 @@
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { search } = require('../templates/search.js');
const { search, highlight } = require('../templates/search.js');
const dist = process.argv[2] || path.join(__dirname, '../dist');
const info = JSON.parse(fs.readFileSync(path.join(dist, 'build-info.json')));
const index = JSON.parse(fs.readFileSync(path.join(dist, info.searchIndex)));
@@ -9,6 +9,45 @@ assert(search(index, '拥塞控制').some(r => r.path.includes('计算机网络
assert(search(index, '检索增强生成').some(r => r.path === '/notes/大模型应用' && r.id === '三、检索增强生成'));
assert(search(index, 'Token 分词').some(r => r.path === '/notes/大模型应用' && r.id === 'token-与分词'));
assert.equal(search(index, '').length, 0);
const ranking = { documents: [
{ title: '学习路线 - 示例', path: '/notes/学习路线 - 示例', sections: [{ title: '第 1 天:拥塞控制', id: 'day', text: '阅读拥塞控制' }] },
{ title: '网络', path: '/notes/网络', sections: [
{ title: 'TCP 拥塞控制', id: 'tcp', text: '拥塞控制用于……' },
{ title: 'A1 线程池的拒绝策略', id: 'a1', text: '线程池实验' },
{ title: 'ThreadPoolExecutor', id: 'pool', text: '线程池指的是……' },
{ title: 'Thread Local Storage', id: 'tls', text: '线程本地存储' },
{ title: 'Agentic RAG', id: 'rag', text: '检索' },
] },
] };
assert.equal(search(ranking, '拥塞控制')[0].id, 'tcp', '讲解正文排在学习路线之前');
assert.equal(search(ranking, '线程池')[0].id, 'pool', '讲解正文排在附录实验之前');
assert.equal(search(ranking, 'rag')[0].id, 'rag', '英文词按完整单词优先');
assert.equal(search(ranking, '第 1 天')[0].id, 'day', '学习路线仍能搜到');
const phrasing = { documents: [
{ title: '死锁', path: '/notes/死锁', sections: [
{ title: '死锁预防', id: 'pre', text: '破坏某个必要条件' },
{ title: '必要条件', id: 'cond', text: '只有以下四个条件同时成立时才会发生死锁' },
] },
{ title: '容器', path: '/notes/容器', sections: [
{ title: 'HashMap', id: 'map', text: '哈希冲突用拉链法解决,扩容时容量翻倍' },
{ title: '与 Hashtable 的比较', id: 'cmp', text: 'HashMap 不是线程安全的' },
] },
{ title: 'Java 虚拟机', path: '/notes/jvm', sections: [{ title: '垃圾收集器', id: 'gc', text: 'G1' }] },
{ title: '57.1 和为 S 的两个数字', path: '/notes/57.1', sections: [
{ title: '57.1 和为 S 的两个数字', id: '', text: '' }, { title: '57.1 和为 S 的两个数字', id: 'h1', text: '' },
] },
] };
assert.equal(search(phrasing, '死锁的必要条件')[0].id, 'cond', '去掉问法后,小节标题正好匹配的排在前面');
assert.equal(search(phrasing, '死锁的四个条件')[0].id, 'cond', '去掉问法后再搜');
assert(search(phrasing, '同时成立的四条件').fuzzy && search(phrasing, '同时成立的四条件')[0].id === 'cond', '没有完全匹配时按词组找相近的小节,并标出来');
assert.equal(search(phrasing, 'hashmap扩容')[0].id, 'map', '中英文连写时拆开');
assert.equal(search(phrasing, '散列冲突')[0].id, 'map', '术语的另一种说法');
assert.equal(search(phrasing, '垃圾回收器')[0].id, 'gc', '垃圾回收按垃圾收集搜索');
assert.equal(search(phrasing, 'HashMap和Hashtable的区别')[0].id, 'cmp', '“和……的区别”问法');
assert.equal(search(phrasing, '和为 S').length, 1, '没有正文的开头部分不和一级标题重复出现');
assert.equal(search(phrasing, '什么是').length, 0, '只有问法时没有结果');
assert.equal(highlight('a<b 的 TCP 与 tcp', 'tcp'), 'a&lt;b 的 <mark>TCP</mark> 与 <mark>tcp</mark>', '搜索词高亮不区分大小写,其余文字转义');
assert.equal(highlight('&amp; (x)', 'amp (x)'), '&amp;<mark>amp</mark>; <mark>(x)</mark>', '高亮先切分再转义,正则字符按字面匹配');
const sample = { documents: [{ title: '数据库', path: '/notes/示例', sections: [
{ title: '事务', id: '事务', text: '一致性 '.repeat(20) },
{ title: '一致性', id: '一致性', text: 'SQL 与数据库' },