test(ai-review): 補 usageSection 結構、resolveMissingLineNumbers 例外與誤報混合平行測試
This commit is contained in:
@@ -307,6 +307,20 @@ describe('postFindingsReview', () => {
|
||||
assert.equal(reviewCalls[0].body, reviewCalls[0].body.trimEnd());
|
||||
});
|
||||
|
||||
it('appends usageSection verbatim after the stats block without altering structure', async () => {
|
||||
const reviewCalls = [];
|
||||
const usageSection = '## 🤖 AI 助理使用量\n\n| x | y |\n| - | - |\n| 1 | 2 |';
|
||||
await postFindingsReview([
|
||||
{ level: 'warning', role: 'Leo', location: 'app/b.js:20', suggestion: 'W', is_new: true },
|
||||
], { postReview: async (args) => { reviewCalls.push(args); }, usageSection });
|
||||
|
||||
const body = reviewCalls[0].body;
|
||||
// 統計區塊在前、usageSection 原樣接在後(中間一個空行);不交錯、不被竄改
|
||||
assert.ok(body.startsWith('## AI Code Review 統計'));
|
||||
assert.ok(body.endsWith(usageSection));
|
||||
assert.match(body, /## AI Code Review 統計[\s\S]*\n\n## 🤖 AI 助理使用量/);
|
||||
});
|
||||
|
||||
it('counts both new and old findings in the summary but only inline-comments new ones', async () => {
|
||||
const reviewCalls = [];
|
||||
await postFindingsReview([
|
||||
|
||||
@@ -244,6 +244,23 @@ describe('findings exclusions', () => {
|
||||
assert.equal(result.length, 1); // 只有明確 false_positive 才剔除,其餘保守保留
|
||||
});
|
||||
|
||||
it('keeps failed and confirmed, drops only confirmed false positives (mixed parallel)', async () => {
|
||||
const findings = [
|
||||
{ level: 'warning', role: 'A', location: 'a.js:1', problem: 'p', suggestion: 'fail' },
|
||||
{ level: 'warning', role: 'B', location: 'b.js:2', problem: 'p', suggestion: 'fp' },
|
||||
{ level: 'warning', role: 'C', location: 'c.js:3', problem: 'p', suggestion: 'ok' },
|
||||
];
|
||||
const chatFn = async (_sys, user) => {
|
||||
const loc = JSON.parse(user).location;
|
||||
if (loc === 'a.js:1') throw new Error('boom'); // 失敗 → 保守保留
|
||||
if (loc === 'b.js:2') return { verdict: 'false_positive' };// 誤報 → 剔除
|
||||
return { verdict: 'confirmed' }; // 成立 → 保留
|
||||
};
|
||||
|
||||
const result = await filterFalsePositivesWithAI(findings, [], chatFn);
|
||||
assert.deepEqual(result.map(f => f.location).sort(), ['a.js:1', 'c.js:3']);
|
||||
});
|
||||
|
||||
it('resolveMissingLineNumbers fills missing line numbers by re-asking the role', async () => {
|
||||
const findings = [
|
||||
{ level: 'critical', role: 'Maya', location: 'app/a.js', problem: 'p', suggestion: 's' },
|
||||
@@ -281,6 +298,17 @@ describe('findings exclusions', () => {
|
||||
assert.equal(n, 3); // 嘗試 3 次後放棄
|
||||
});
|
||||
|
||||
it('resolveMissingLineNumbers swallows chatFn exceptions and keeps the filename', async () => {
|
||||
const findings = [{ level: 'warning', role: 'Leo', location: 'app/z.js', problem: 'p', suggestion: 's' }];
|
||||
let n = 0;
|
||||
const chatFn = async () => { n += 1; throw new Error('LLM down'); };
|
||||
|
||||
await resolveMissingLineNumbers(findings, 'd', { chatFn, getRole: () => null, maxAttempts: 2 });
|
||||
|
||||
assert.equal(findings[0].location, 'app/z.js'); // 例外被吞、保留檔名、不中斷流程
|
||||
assert.equal(n, 2); // 每次嘗試仍呼叫、受上限約束
|
||||
});
|
||||
|
||||
it('logs exclusions file metadata and repo state when loading exclusions', () => {
|
||||
const fullPath = path.join(workspace, EXCLUSIONS_PATH);
|
||||
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
||||
|
||||
Reference in New Issue
Block a user