fix: truncate article titles to safe UTF-8 budget

This commit is contained in:
Longtail committed 2026-10-31 18:38:41 +08:00
1 parent 24a73b19c0
commit 7ab0bc3485
7 files changed
+115 -15

No files matched your search

+37 -2
View File
@@ -29,12 +29,11 @@ test('测试文章:标题、3 张配图、插入顺序、来源与段落完整
assert.equal(output, originalBody);
});
test('缺图、远程图片、超出目录、超大图片与超长标题在上传前被拒绝', () => {
test('缺图、远程图片、超出目录与超大图片在上传前被拒绝', () => {
assert.throws(() => core.compile('# 标题\n\n![](missing.jpg)', 'a.md', new Map()), /找不到配图/);
assert.throws(() => core.compile('# 标题\n\n![](https://x/a.jpg)', 'a.md', new Map()), /目录内/);
assert.throws(() => core.imagePath('a.md', '../secret.jpg'), /超出/);
assert.throws(() => core.imagePath('a.md', '%2fetc/passwd'), /相对路径/);
assert.throws(() => core.compile('# ' + '长'.repeat(81) + '\n正文', 'a.md', new Map()), /80/);
assert.throws(() => core.compile('# 标题\n\n![](big.png)', 'a.md', new Map([['big.png', {size:20*1024*1024}]])), /20 MB/);
});
@@ -209,3 +208,39 @@ test('正文图片尚在加载时等待 load;终止后释放等待', async ()
const cancelled=core.verifyEditorImages({querySelectorAll:()=>[pending]},['8'],controller.signal);
controller.abort();await assert.rejects(cancelled,/终止/);assert.equal(pending.events.size,0);
});
test('标题按 UTF-8 预算截断,目录和文章包保持一致且重复处理稳定', async () => {
const cases = [
['A'.repeat(75), 'A'.repeat(75)],
['A'.repeat(76), 'A'.repeat(75) + '...'],
['中'.repeat(25), '中'.repeat(25)],
['中'.repeat(26), '中'.repeat(25) + '...'],
['A中,'.repeat(12), 'A中,'.repeat(10) + 'A中...'],
['😀'.repeat(20), '😀'.repeat(18) + '...'],
];
for (const [title, expected] of cases) {
assert.equal(core.shortTitle(title), expected);
assert.equal(core.shortTitle(expected), expected);
assert.ok(Buffer.byteLength(expected) <= 78);
const markdown = '# ' + title + '\n正文';
const direct = core.compile(markdown, 'a.md', new Map());
const packaged = await core.preparePackage({schemaVersion:1, markdown, title, images:[]});
assert.equal(direct.title, expected);
assert.equal(packaged.title, expected);
const python = execFileSync('python3', ['-c', 'import sys; from articles import short_title; print(short_title(sys.argv[1]), end="")', title], {cwd:path.join(__dirname, '..'), encoding:'utf8'});
assert.equal(python, expected);
}
});
test('长标题预览、实际填写和返回结果一致', async () => {
const h = harness();
const title = '新闻,'.repeat(20);
await h.api.stagePackage({schemaVersion:1, markdown:'# ' + title + '\n正文', images:[]});
const expected = '新闻,'.repeat(8) + '新...';
assert.equal(h.api.getState().title, expected);
const result = await h.api.importPrepared();
assert.equal(h.ids.get('subject').value, expected);
assert.equal(result.title, expected);
assert.equal(h.requests.length, 0);
});