397777089e
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
75 lines
3.8 KiB
JavaScript
75 lines
3.8 KiB
JavaScript
// tools/graph-radar.test.mjs
|
|
import { describe, it, expect } from 'vitest';
|
|
import { buildGraphRadar } from './graph-radar.mjs';
|
|
|
|
const graph = {
|
|
nodes: [
|
|
{ id: 'x', label: 'X', source_file: 'tools/x.mjs' },
|
|
{ id: 'y', label: 'Y', source_file: 'tools/y.mjs' },
|
|
{ id: 'z', label: 'Z', source_file: 'tools/z.mjs' },
|
|
],
|
|
links: [
|
|
{ source: 'x', target: 'y', relation: 'references' },
|
|
{ source: 'z', target: 'x', relation: 'references' },
|
|
],
|
|
};
|
|
|
|
describe('buildGraphRadar (§5.7 граф-радар)', () => {
|
|
it('тронут x → соседи y и z в чек-листе (addressed:false)', () => {
|
|
const r = buildGraphRadar({ touchedFiles: ['tools/x.mjs'], graph });
|
|
const ids = r.neighbors.map((n) => n.node).sort();
|
|
expect(ids).toEqual(['y', 'z']);
|
|
expect(r.neighbors.every((n) => n.addressed === false)).toBe(true);
|
|
expect(r.neighbors.find((n) => n.node === 'y').viaTouched).toBe('x');
|
|
});
|
|
it('сосед, который САМ тронут, не попадает в чек-лист (уже адресован)', () => {
|
|
const r = buildGraphRadar({ touchedFiles: ['tools/x.mjs', 'tools/y.mjs'], graph });
|
|
expect(r.neighbors.map((n) => n.node)).toEqual(['z']); // y тронут → не флагуем
|
|
});
|
|
it('нет тронутых узлов в графе → пустой чек-лист', () => {
|
|
expect(buildGraphRadar({ touchedFiles: ['tools/nope.mjs'], graph }).neighbors).toEqual([]);
|
|
});
|
|
it('битый граф/входы → пусто, не крашит', () => {
|
|
expect(buildGraphRadar({ touchedFiles: null, graph: null }).neighbors).toEqual([]);
|
|
expect(buildGraphRadar({ touchedFiles: ['a'], graph: { nodes: 'x', links: 1 } }).neighbors).toEqual([]);
|
|
});
|
|
|
|
// F-F1: слепота радара видна — подано файлов > 0, найдено узлов 0
|
|
it('F-F1: summary.touchedFiles показывает поданное; слепота = touchedFiles>0 ∧ touchedNodes=0', () => {
|
|
const blind = buildGraphRadar({ touchedFiles: ['tools/nope.mjs'], graph });
|
|
expect(blind.summary.touchedFiles).toBe(1);
|
|
expect(blind.summary.touchedNodes).toBe(0);
|
|
const ok = buildGraphRadar({ touchedFiles: ['tools/x.mjs'], graph });
|
|
expect(ok.summary.touchedFiles).toBe(1);
|
|
expect(ok.summary.touchedNodes).toBe(1);
|
|
});
|
|
|
|
// F-F2: нормализация путей — backslash и ./-префикс не дают тихий промах
|
|
it('F-F2: windows-backslash и ./-префикс в touchedFiles находят узел', () => {
|
|
const r1 = buildGraphRadar({ touchedFiles: ['tools\\x.mjs'], graph });
|
|
expect(r1.summary.touchedNodes).toBe(1);
|
|
expect(r1.neighbors.map((n) => n.node).sort()).toEqual(['y', 'z']);
|
|
const r2 = buildGraphRadar({ touchedFiles: ['./tools/x.mjs'], graph });
|
|
expect(r2.summary.touchedNodes).toBe(1);
|
|
});
|
|
it('F-F2: backslash в source_file графа тоже нормализуется', () => {
|
|
const g = {
|
|
nodes: [
|
|
{ id: 'a', label: 'A', source_file: 'tools\\a.mjs' },
|
|
{ id: 'b', label: 'B', source_file: 'tools/b.mjs' },
|
|
],
|
|
links: [{ source: 'a', target: 'b' }],
|
|
};
|
|
const r = buildGraphRadar({ touchedFiles: ['tools/a.mjs'], graph: g });
|
|
expect(r.neighbors.map((n) => n.node)).toEqual(['b']);
|
|
});
|
|
|
|
// F-F4: выходные элементы заморожены — машинное addressed:true бросает (L2-пол)
|
|
it('F-F4: элементы neighbors заморожены, мутация addressed бросает TypeError', () => {
|
|
const r = buildGraphRadar({ touchedFiles: ['tools/x.mjs'], graph });
|
|
expect(r.neighbors.length).toBeGreaterThan(0);
|
|
expect(r.neighbors.every((n) => Object.isFrozen(n))).toBe(true);
|
|
expect(() => { r.neighbors[0].addressed = true; }).toThrow(TypeError);
|
|
});
|
|
});
|