Files
archived-gitea-ai-assistant/src/review/__tests__/judge-agent.test.ts
jeffusion 318e6d3688 build: replace tslint with Biome for code quality
- Add @biomejs/biome as dev dependency
- Remove deprecated tslint dependency
- Add biome.json with project-specific rules
- Update lint script to use Biome
- Apply Biome auto-fixes across codebase
2026-03-03 17:03:23 +08:00

138 lines
5.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, test } from 'bun:test';
import { JudgeAgent } from '../agents/judge-agent';
import type { Finding } from '../types';
type TestFinding = Omit<Finding, 'id' | 'runId' | 'published'>;
function makeFinding(overrides: Partial<TestFinding> = {}): TestFinding {
return {
fingerprint: `fp-${Math.random().toString(36).slice(2, 8)}`,
category: 'correctness',
severity: 'medium',
confidence: 0.8,
path: 'src/foo.ts',
line: 10,
title: 'Test issue',
detail: 'Detail',
evidence: 'Evidence',
suggestion: 'Fix it',
...overrides,
};
}
describe('JudgeAgent', () => {
const judge = new JudgeAgent();
// ─── Empty input ───
test('empty findings → summary says 未发现', () => {
const result = judge.judge([]);
expect(result.findings).toHaveLength(0);
expect(result.summaryMarkdown).toContain('未发现');
});
// ─── Deduplication by fingerprint ───
test('duplicate fingerprints → keeps highest weighted', () => {
const fp = 'same-fingerprint';
const findings: TestFinding[] = [
makeFinding({ fingerprint: fp, severity: 'low', confidence: 0.9 }), // weight: 1 * 0.9 = 0.9
makeFinding({ fingerprint: fp, severity: 'high', confidence: 0.5 }), // weight: 3 * 0.5 = 1.5 ← winner
makeFinding({ fingerprint: fp, severity: 'medium', confidence: 0.6 }), // weight: 2 * 0.6 = 1.2
];
const result = judge.judge(findings);
expect(result.findings).toHaveLength(1);
expect(result.findings[0].severity).toBe('high');
expect(result.findings[0].confidence).toBe(0.5);
});
test('same fingerprint same weight → first one wins (no override)', () => {
const fp = 'dup-fp';
const findings: TestFinding[] = [
makeFinding({ fingerprint: fp, severity: 'high', confidence: 0.5, title: 'First' }),
makeFinding({ fingerprint: fp, severity: 'high', confidence: 0.5, title: 'Second' }),
];
const result = judge.judge(findings);
expect(result.findings).toHaveLength(1);
// Same weight → second does NOT override (currentWeight > existingWeight is strict >)
expect(result.findings[0].title).toBe('First');
});
// ─── Sorting by severity × confidence ───
test('findings sorted by weight descending', () => {
const findings: TestFinding[] = [
makeFinding({ fingerprint: 'a', severity: 'low', confidence: 0.9 }), // 1 * 0.9 = 0.9
makeFinding({ fingerprint: 'b', severity: 'high', confidence: 0.8 }), // 3 * 0.8 = 2.4
makeFinding({ fingerprint: 'c', severity: 'medium', confidence: 0.7 }), // 2 * 0.7 = 1.4
];
const result = judge.judge(findings);
expect(result.findings).toHaveLength(3);
expect(result.findings[0].fingerprint).toBe('b'); // weight 2.4
expect(result.findings[1].fingerprint).toBe('c'); // weight 1.4
expect(result.findings[2].fingerprint).toBe('a'); // weight 0.9
});
// ─── Summary text ───
test('summary counts by severity', () => {
const findings: TestFinding[] = [
makeFinding({ fingerprint: 'a', severity: 'high', confidence: 0.9 }),
makeFinding({ fingerprint: 'b', severity: 'high', confidence: 0.85 }),
makeFinding({ fingerprint: 'c', severity: 'medium', confidence: 0.8 }),
makeFinding({ fingerprint: 'd', severity: 'low', confidence: 0.7 }),
];
const result = judge.judge(findings);
expect(result.summaryMarkdown).toContain('4 个问题');
expect(result.summaryMarkdown).toContain('high 2');
expect(result.summaryMarkdown).toContain('medium 1');
expect(result.summaryMarkdown).toContain('low 1');
});
test('single finding → counts correctly', () => {
const findings: TestFinding[] = [
makeFinding({ fingerprint: 'x', severity: 'medium', confidence: 0.8 }),
];
const result = judge.judge(findings);
expect(result.summaryMarkdown).toContain('1 个问题');
expect(result.summaryMarkdown).toContain('high 0');
expect(result.summaryMarkdown).toContain('medium 1');
expect(result.summaryMarkdown).toContain('low 0');
});
// ─── Dedup + sort combined ───
test('dedup then sort: complex scenario', () => {
const findings: TestFinding[] = [
makeFinding({ fingerprint: 'x', severity: 'low', confidence: 0.3 }), // weight 0.3 — will be overridden
makeFinding({ fingerprint: 'y', severity: 'high', confidence: 0.9 }), // weight 2.7 — unique
makeFinding({ fingerprint: 'x', severity: 'medium', confidence: 0.8 }), // weight 1.6 — overrides x
makeFinding({ fingerprint: 'z', severity: 'high', confidence: 0.5 }), // weight 1.5 — unique
];
const result = judge.judge(findings);
expect(result.findings).toHaveLength(3); // x, y, z (deduped)
// Sorted by weight: y(2.7) > x(1.6) > z(1.5)
expect(result.findings[0].fingerprint).toBe('y');
expect(result.findings[1].fingerprint).toBe('x');
expect(result.findings[1].severity).toBe('medium'); // overridden version
expect(result.findings[2].fingerprint).toBe('z');
});
// ─── All same severity ───
test('all high severity → sorted by confidence descending', () => {
const findings: TestFinding[] = [
makeFinding({ fingerprint: 'a', severity: 'high', confidence: 0.5 }),
makeFinding({ fingerprint: 'b', severity: 'high', confidence: 0.9 }),
makeFinding({ fingerprint: 'c', severity: 'high', confidence: 0.7 }),
];
const result = judge.judge(findings);
expect(result.findings[0].fingerprint).toBe('b');
expect(result.findings[1].fingerprint).toBe('c');
expect(result.findings[2].fingerprint).toBe('a');
});
// ─── Return type structure ───
test('result has summaryMarkdown and findings', () => {
const result = judge.judge([]);
expect(result).toHaveProperty('summaryMarkdown');
expect(result).toHaveProperty('findings');
expect(typeof result.summaryMarkdown).toBe('string');
expect(Array.isArray(result.findings)).toBe(true);
});
});