Assessor_2.0/tests/architecture/core-areas.test.ts

64 lines
2.9 KiB
TypeScript

import { dirname, join, resolve } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { beforeAll, describe, expect, it } from 'vitest';
// The Core guard's area table (AGENTS.md, "Core Engine and engines"): engine paths come before the
// Core areas, an unregistered source path stays Core, and a bare folder name belongs to the prefix
// it names, so renaming a whole engine folder is not mistaken for a Core change.
const root = resolve(dirname(fileURLToPath(import.meta.url)), '../..');
interface AreaTable {
classifyPath(relative: string | null): string | null;
relativeToProject(filePath: string, projectDir: string): string | null;
resolveAreaName(raw: string): string | null;
isReleased(area: string, releasedAreas: string[]): boolean;
}
let areas: AreaTable;
beforeAll(async () => {
areas = await import(/* @vite-ignore */ pathToFileURL(join(root, '.claude', 'hooks', 'core-areas.mjs')).href) as AreaTable;
});
describe('Core guard area table', () => {
it.each([
'src/compliance', 'src/compliance/', 'src/compliance/ui/regulatorymappingpanel.tsx',
'server/compliance', 'tests/compliance', 'src/assessment-context', 'src/reporting', 'server/reporting'
])('treats engine path %s as engine code', path => {
expect(areas.classifyPath(path)).toBeNull();
});
it.each([
['src/compliance-x', 'Unclassified Source'],
['src/compliance-x/file.ts', 'Unclassified Source'],
['src/newthing', 'Unclassified Source'],
['src/persistence', 'Store'],
['src/persistence/local-assessor-repository.ts', 'Store'],
['server/postgres', 'Store'],
['src/app', 'Presentation'],
['src/features/finding-reader/findingreader.tsx', 'Presentation'],
['server/index.ts', 'Platform'],
['tests/architecture/core-areas.test.ts', 'Core Tests'],
['agents.md', 'Governance'],
['.claude/hooks', 'Governance'],
['src/domain/review.ts', 'Client Records']
])('keeps %s in Core area %s', (path, area) => {
expect(areas.classifyPath(path)).toBe(area);
});
it('leaves paths outside the project and documentation unguarded', () => {
expect(areas.classifyPath(null)).toBeNull();
expect(areas.relativeToProject(join(root, '..', 'elsewhere.ts'), root)).toBeNull();
expect(areas.classifyPath('docs/implementation_plan.md')).toBeNull();
expect(areas.relativeToProject(join(root, 'src', 'Compliance', 'X.ts'), root)).toBe('src/compliance/x.ts');
});
it('resolves release names and never lets "alle" cover Governance', () => {
expect(areas.resolveAreaName(' Core Tests ')).toBe('Core Tests');
expect(areas.resolveAreaName('unclassified source')).toBe('Unclassified Source');
expect(areas.resolveAreaName('compliance')).toBeNull();
expect(areas.isReleased('Store', ['alle'])).toBe(true);
expect(areas.isReleased('Governance', ['alle'])).toBe(false);
expect(areas.isReleased('Governance', ['Governance'])).toBe(true);
expect(areas.isReleased('Store', ['Platform'])).toBe(false);
});
});