import { describe, expect, it } from 'vitest'; import { bestNearbyCardCandidate, graphEdgeCrossingCount, graphLineDistanceToPoint, graphLineSegmentsIntersect, leastCrossingCardCandidate } from '../../src/features/mitre-graph/graph-card-edge-avoidance'; describe('graph card edge avoidance', () => { const segments = [{ x1: -100, y1: 50, x2: 300, y2: 50 }]; it('detects a graph edge crossing the card body', () => { expect(graphEdgeCrossingCount({ x: 0, y: 0 }, 100, 100, segments)).toBe(1); expect(graphEdgeCrossingCount({ x: 0, y: 100 }, 100, 100, segments)).toBe(0); }); it('prefers the first candidate with fewer red-edge crossings', () => { expect(leastCrossingCardCandidate( [{ x: 0, y: 0 }, { x: 0, y: 100 }], 100, 100, segments )).toEqual({ x: 0, y: 100 }); }); it('keeps a card near its node instead of choosing a very distant crossing-free position', () => { expect(bestNearbyCardCandidate( [{ x: 0, y: 0 }, { x: 1200, y: 1200 }], { x: 0, y: 0 }, 100, 100, segments )).toEqual({ x: 0, y: 0 }); }); it('detects connector crossings and connector proximity to unrelated nodes', () => { expect(graphLineSegmentsIntersect(0, 0, 100, 100, 0, 100, 100, 0)).toBe(true); expect(graphLineSegmentsIntersect(0, 0, 10, 0, 20, 0, 30, 0)).toBe(false); expect(graphLineDistanceToPoint({ x1: 0, y1: 0, x2: 100, y2: 0 }, 50, 10)).toBe(10); }); it('uses layout penalties to avoid a nearby connector conflict', () => { expect(bestNearbyCardCandidate( [{ x: 0, y: 0 }, { x: 100, y: 0 }], { x: 0, y: 0 }, 100, 100, [], candidate => candidate.x === 0 ? 5000 : 0 )).toEqual({ x: 100, y: 0 }); }); });