75 lines
3.0 KiB
TypeScript
75 lines
3.0 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { aggregateSummary, createAssetResult, strongestEvidence, verdictFromEvidence } from '../src/shared/status';
|
|
import type { Evidence } from '../src/shared/types';
|
|
|
|
const evidence = (overrides: Partial<Evidence>): Evidence => ({
|
|
id: crypto.randomUUID(),
|
|
kind: 'c2pa',
|
|
strength: 'none',
|
|
verdict: 'unknown',
|
|
title: 'Evidence',
|
|
detail: 'Test evidence',
|
|
...overrides
|
|
});
|
|
|
|
describe('evidence precedence', () => {
|
|
it('treats invalid credentials as stronger than positive evidence', () => {
|
|
const items = [
|
|
evidence({ strength: 'verified', verdict: 'ai' }),
|
|
evidence({ strength: 'invalid', verdict: 'invalid' })
|
|
];
|
|
expect(strongestEvidence(items)).toBe('invalid');
|
|
expect(verdictFromEvidence(items)).toBe('invalid');
|
|
});
|
|
|
|
it('never turns empty evidence into a human-origin assertion', () => {
|
|
const result = createAssetResult('one', 'image', 'Unsigned image', []);
|
|
expect(result.verdict).toBe('unknown');
|
|
expect(result.strength).toBe('none');
|
|
});
|
|
});
|
|
|
|
describe('page aggregation', () => {
|
|
const unknownPage = createAssetResult('page', 'page', 'Page', []);
|
|
|
|
it('reports verified AI when a trusted AI credential is present', () => {
|
|
const image = createAssetResult('image', 'image', 'Image', [
|
|
evidence({ strength: 'verified', verdict: 'ai' })
|
|
]);
|
|
expect(aggregateSummary(unknownPage, [image], [], 1, 0).status).toBe('verified-ai');
|
|
});
|
|
|
|
it('reports mixed provenance when AI and non-AI assertions coexist', () => {
|
|
const ai = createAssetResult('ai', 'image', 'AI', [evidence({ strength: 'verified', verdict: 'ai' })]);
|
|
const camera = createAssetResult('camera', 'image', 'Camera', [
|
|
evidence({ strength: 'verified', verdict: 'not-ai-asserted' })
|
|
]);
|
|
expect(aggregateSummary(unknownPage, [ai, camera], [], 2, 0).status).toBe('mixed-provenance');
|
|
});
|
|
|
|
it('prioritises invalid credentials', () => {
|
|
const invalid = createAssetResult('bad', 'image', 'Invalid', [
|
|
evidence({ strength: 'invalid', verdict: 'invalid' })
|
|
]);
|
|
expect(aggregateSummary(unknownPage, [invalid], [], 1, 0).status).toBe('invalid-credential');
|
|
});
|
|
|
|
it('reports suspicion without asserting AI authorship when heuristic clues cross the threshold', () => {
|
|
const suspectedPage = createAssetResult('page', 'page', 'Page', [
|
|
evidence({ kind: 'heuristic', strength: 'clue', category: 'visual', score: 3 }),
|
|
evidence({ kind: 'heuristic', strength: 'clue', category: 'layout', score: 2 })
|
|
]);
|
|
const summary = aggregateSummary(suspectedPage, [], [], 0, 0, 6);
|
|
expect(summary.status).toBe('heuristic-suspected');
|
|
expect(suspectedPage.verdict).toBe('unknown');
|
|
expect(summary.heuristicScore).toBe(6);
|
|
});
|
|
|
|
it('does not elevate a single weak style clue', () => {
|
|
const page = createAssetResult('page', 'page', 'Page', [
|
|
evidence({ kind: 'heuristic', strength: 'clue', category: 'visual', score: 2 })
|
|
]);
|
|
expect(aggregateSummary(page, [], [], 0, 0, 6).status).toBe('no-supported-evidence');
|
|
});
|
|
});
|