/** * normalizeAttachmentIDs 的判据。 * * 每组用例都对应一种**模型真的会写出来的形状**,不是凑覆盖率。 * 尤其是第二条:它是生产事故的原始形状(opencode 连试 6 次、最后放弃整个任务), * 如果哪天有人把 JSON 字符串分支删掉,这条会立刻红。 */ import assert from 'node:assert/strict'; import { test } from 'node:test'; import { normalizeAttachmentIDs } from '../lib/attachment-ids.js'; let pass = 0; let fail = 0; const check = (name, ok, detail = '') => { if (ok) { pass++; console.log(` 通过 ${name}`); } else { fail++; console.log(` 失败 ${name}${detail ? ' — ' + detail : ''}`); } }; const ID = '10e73e9f-c2a9-4226-bdb5-34ef1b340eb8'; const ID2 = '5f1c2b3a-1111-2222-3333-444455556666'; // 数组:契约要求的形状 { const got = normalizeAttachmentIDs([ID]); check('数组原样通过', got.length === 1 && got[0] === ID, JSON.stringify(got)); const two = normalizeAttachmentIDs([ID, ID2]); check('多元素数组保序', two.length === 2 && two[0] === ID && two[1] === ID2, JSON.stringify(two)); } // JSON 数组字符串:**事故形状** { const got = normalizeAttachmentIDs(JSON.stringify([ID])); check( 'JSON 数组字符串被解析(事故形状)', got.length === 1 && got[0] === ID, `得到 ${JSON.stringify(got)} —— 这一条红了就说明事故会复发` ); const two = normalizeAttachmentIDs(JSON.stringify([ID, ID2])); check('多元素 JSON 字符串保序', two.length === 2 && two[1] === ID2, JSON.stringify(two)); } // 单个 id:模型常见的偷懒写法,拒绝它只会换来一次重试 { const got = normalizeAttachmentIDs(ID); check('裸单个 id 被接受', got.length === 1 && got[0] === ID, JSON.stringify(got)); check( '裸单个 id 不会被误切(uuid 含 - 但不含 , 与空白)', got[0] === ID, got[0] ); } // 逗号 / 空白分隔 { const got = normalizeAttachmentIDs(`${ID}, ${ID2}`); check('逗号分隔被切开', got.length === 2 && got[1] === ID2, JSON.stringify(got)); const got2 = normalizeAttachmentIDs(`${ID} ${ID2}`); check('空白分隔被切开', got2.length === 2 && got2[1] === ID2, JSON.stringify(got2)); } // 杂质:丢坏的留好的(三个里坏一个,不该变成一个都不发) { const got = normalizeAttachmentIDs([null, ID, 3, '', undefined, ID2]); check( '混杂 null/数字/空串时只保留合法 id', got.length === 2 && got[0] === ID && got[1] === ID2, JSON.stringify(got) ); const got2 = normalizeAttachmentIDs(JSON.stringify([null, ID])); check('JSON 字符串里的杂质同样被过滤', got2.length === 1 && got2[0] === ID, JSON.stringify(got2)); } // 空值:不能返回 null(调用方会当数组用) { for (const v of [null, undefined, '', ' ', []]) { const got = normalizeAttachmentIDs(v); check( `空值 ${JSON.stringify(v)} → 空数组(且不是 null)`, Array.isArray(got) && got.length === 0, JSON.stringify(got) ); } } // 非法输入不该抛异常:抛出去会让整个 send_mail 失败, // 而那本来只需要「这个字段作废」 { let threw = null; try { normalizeAttachmentIDs({ not: 'a list' }); normalizeAttachmentIDs(42); normalizeAttachmentIDs('[坏 JSON'); } catch (e) { threw = e; } check('非法输入不抛异常', threw === null, String(threw)); } // 反向对照:坏 JSON 字符串不该被当成 id 原样带走 { const got = normalizeAttachmentIDs('[坏 JSON'); check( '坏 JSON 字符串不产生伪造的 id', !got.includes('[坏 JSON'), JSON.stringify(got) ); } console.log(`\n附件 id 归一:${pass} 通过,${fail} 失败`); process.exit(fail === 0 ? 0 : 1);