mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-18 20:15:14 +02:00
[pitboss/grind] deferred session-0022 (20260517T044708Z-e058)
This commit is contained in:
parent
01eb67e1f9
commit
f4793b0439
11 changed files with 559 additions and 20 deletions
|
|
@ -49,6 +49,29 @@ describe('getNodeStyle', () => {
|
|||
const s = getNodeStyle('Call', 'callgraph', { isRecursive: true });
|
||||
expect(s.fill).toBe('#5a5042');
|
||||
});
|
||||
|
||||
it('returns a double shape for surface entry-point nodes', () => {
|
||||
const s = getNodeStyle('EntryPoint', 'surface');
|
||||
expect(s.shape).toBe('double');
|
||||
expect(s.fill).toBe('#1c5c38');
|
||||
});
|
||||
|
||||
it('returns a terminal shape for surface dangerous-local nodes', () => {
|
||||
const s = getNodeStyle('DangerousLocal', 'surface');
|
||||
expect(s.shape).toBe('terminal');
|
||||
expect(s.fill).toBe('#9d2f25');
|
||||
});
|
||||
|
||||
it('returns a warning fill for surface data-store nodes', () => {
|
||||
const s = getNodeStyle('DataStore', 'surface');
|
||||
expect(s.fill).toBe('#8c6310');
|
||||
expect(s.shape).toBe('rect');
|
||||
});
|
||||
|
||||
it('returns an accent fill for surface external-service nodes', () => {
|
||||
const s = getNodeStyle('ExternalService', 'surface');
|
||||
expect(s.fill).toBe('#0b3d2a');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getEdgeStyle', () => {
|
||||
|
|
@ -90,4 +113,26 @@ describe('getEdgeStyle', () => {
|
|||
const s = getEdgeStyle('Call', 'callgraph');
|
||||
expect(s.dash).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns a dashed style for surface auth_required_on edges', () => {
|
||||
const s = getEdgeStyle('auth_required_on', 'surface');
|
||||
expect(s.dash).toEqual([2, 4]);
|
||||
});
|
||||
|
||||
it('returns a solid danger color for surface reaches edges', () => {
|
||||
const s = getEdgeStyle('reaches', 'surface');
|
||||
expect(s.color).toBe('#9d2f25');
|
||||
expect(s.dash).toEqual([]);
|
||||
});
|
||||
|
||||
it('returns a dashed success style for surface triggers edges', () => {
|
||||
const s = getEdgeStyle('triggers', 'surface');
|
||||
expect(s.dash).toEqual([4, 3]);
|
||||
});
|
||||
|
||||
it('returns a fallback style for unknown surface edge kinds', () => {
|
||||
const s = getEdgeStyle('mystery', 'surface');
|
||||
expect(s.color).toContain('rgba');
|
||||
expect(s.dash).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
110
frontend/src/test/graph/surfaceAdapter.test.ts
Normal file
110
frontend/src/test/graph/surfaceAdapter.test.ts
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { adaptSurfaceMap, SURFACE_NODE_KIND } from '@/graph/adapters/surface';
|
||||
import type { SurfaceMap } from '@/api/types';
|
||||
|
||||
const SAMPLE: SurfaceMap = {
|
||||
nodes: [
|
||||
{
|
||||
node: 'entry_point',
|
||||
location: { file: 'app.py', line: 10, col: 0 },
|
||||
framework: 'flask',
|
||||
method: 'POST',
|
||||
route: '/api/run',
|
||||
handler_name: 'run',
|
||||
handler_location: { file: 'app.py', line: 12, col: 2 },
|
||||
auth_required: false,
|
||||
},
|
||||
{
|
||||
node: 'data_store',
|
||||
location: { file: 'db.py', line: 40, col: 0 },
|
||||
kind: 'sql',
|
||||
label: 'orders',
|
||||
},
|
||||
{
|
||||
node: 'external_service',
|
||||
location: { file: 'client.py', line: 5, col: 0 },
|
||||
kind: 'http_api',
|
||||
label: 'github.com',
|
||||
},
|
||||
{
|
||||
node: 'dangerous_local',
|
||||
location: { file: 'app.py', line: 24, col: 4 },
|
||||
function_name: 'run',
|
||||
cap_bits: 0x400,
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{ from: 0, to: 3, kind: 'calls' },
|
||||
{ from: 3, to: 1, kind: 'writes_to' },
|
||||
{ from: 0, to: 2, kind: 'talks_to' },
|
||||
],
|
||||
};
|
||||
|
||||
describe('adaptSurfaceMap', () => {
|
||||
it('produces a surface-kind GraphModel', () => {
|
||||
const model = adaptSurfaceMap(SAMPLE);
|
||||
expect(model.kind).toBe('surface');
|
||||
expect(model.nodes).toHaveLength(4);
|
||||
expect(model.edges).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('keys nodes by index so SurfaceEdge.from/to map directly', () => {
|
||||
const model = adaptSurfaceMap(SAMPLE);
|
||||
expect(model.nodes.map((n) => n.key)).toEqual(['0', '1', '2', '3']);
|
||||
expect(model.edges[0]?.source).toBe('0');
|
||||
expect(model.edges[0]?.target).toBe('3');
|
||||
});
|
||||
|
||||
it('maps each SurfaceNode kind to a distinct style discriminator', () => {
|
||||
const model = adaptSurfaceMap(SAMPLE);
|
||||
expect(model.nodes[0]?.kind).toBe(SURFACE_NODE_KIND.entry_point);
|
||||
expect(model.nodes[1]?.kind).toBe(SURFACE_NODE_KIND.data_store);
|
||||
expect(model.nodes[2]?.kind).toBe(SURFACE_NODE_KIND.external_service);
|
||||
expect(model.nodes[3]?.kind).toBe(SURFACE_NODE_KIND.dangerous_local);
|
||||
});
|
||||
|
||||
it('builds entry-point labels from method and route', () => {
|
||||
const model = adaptSurfaceMap(SAMPLE);
|
||||
expect(model.nodes[0]?.label).toBe('POST /api/run');
|
||||
expect(model.nodes[0]?.detail).toBe('flask · run');
|
||||
});
|
||||
|
||||
it('renders dangerous_local cap_bits as hex in detail', () => {
|
||||
const model = adaptSurfaceMap(SAMPLE);
|
||||
expect(model.nodes[3]?.detail).toBe('cap=0x400');
|
||||
});
|
||||
|
||||
it('uses handler_location for entry_point line, location for others', () => {
|
||||
const model = adaptSurfaceMap(SAMPLE);
|
||||
expect(model.nodes[0]?.line).toBe(12);
|
||||
expect(model.nodes[1]?.line).toBe(40);
|
||||
});
|
||||
|
||||
it('emits an auth badge only for entry_points marked auth_required', () => {
|
||||
const protectedEntry = adaptSurfaceMap({
|
||||
nodes: [
|
||||
{
|
||||
...SAMPLE.nodes[0],
|
||||
node: 'entry_point',
|
||||
auth_required: true,
|
||||
} as SurfaceMap['nodes'][0],
|
||||
],
|
||||
edges: [],
|
||||
});
|
||||
expect(protectedEntry.nodes[0]?.badges).toEqual(['auth']);
|
||||
const openEntry = adaptSurfaceMap(SAMPLE);
|
||||
expect(openEntry.nodes[0]?.badges).toBeUndefined();
|
||||
});
|
||||
|
||||
it('produces unique edge keys even for parallel edges of the same kind', () => {
|
||||
const parallel: SurfaceMap = {
|
||||
nodes: SAMPLE.nodes,
|
||||
edges: [
|
||||
{ from: 0, to: 1, kind: 'calls' },
|
||||
{ from: 0, to: 1, kind: 'calls' },
|
||||
],
|
||||
};
|
||||
const model = adaptSurfaceMap(parallel);
|
||||
expect(model.edges[0]?.key).not.toBe(model.edges[1]?.key);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue