diagrams-fable-tauri/tests/validation.test.ts
2026-07-02 23:22:21 +02:00

92 lines
3.0 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import {
canConnectRelations,
canConnectDirections,
checkConnection,
type PortSpec,
} from '../src/model/validation';
const port = (partial: Partial<PortSpec>): PortSpec => ({
id: 'p',
relation: 'water',
direction: 'any',
x: 0,
y: 0,
...partial,
});
describe('relation compatibility', () => {
it('allows same-relation connections', () => {
expect(canConnectRelations('water', 'water')).toBe(true);
expect(canConnectRelations('gas', 'gas')).toBe(true);
expect(canConnectRelations('power', 'power')).toBe(true);
});
it('allows declared cross-relation pairs symmetrically', () => {
expect(canConnectRelations('water', 'heat')).toBe(true);
expect(canConnectRelations('heat', 'water')).toBe(true);
expect(canConnectRelations('sewage', 'water')).toBe(true);
});
it('rejects incompatible relations', () => {
expect(canConnectRelations('water', 'power')).toBe(false);
expect(canConnectRelations('gas', 'water')).toBe(false);
expect(canConnectRelations('signal', 'power')).toBe(false);
});
});
describe('direction compatibility', () => {
it('rejects out→out and in→in', () => {
expect(canConnectDirections('out', 'out')).toBe(false);
expect(canConnectDirections('in', 'in')).toBe(false);
});
it('allows out→in, in→out and any combinations', () => {
expect(canConnectDirections('out', 'in')).toBe(true);
expect(canConnectDirections('in', 'out')).toBe(true);
expect(canConnectDirections('any', 'out')).toBe(true);
expect(canConnectDirections('any', 'any')).toBe(true);
});
});
describe('checkConnection scenarios', () => {
it('pump discharge (water out) → consumer water inlet: allowed', () => {
const r = checkConnection(
port({ id: 'out', relation: 'water', direction: 'out' }),
port({ id: 'waterIn', relation: 'water', direction: 'in' }),
);
expect(r.ok).toBe(true);
});
it('power supply → water port: rejected with reason', () => {
const r = checkConnection(
port({ id: 'out', relation: 'power', direction: 'out' }),
port({ id: 'in', relation: 'water', direction: 'in' }),
);
expect(r.ok).toBe(false);
expect(r.reason).toMatch(/Incompatible relations/);
});
it('two source outlets: rejected by direction', () => {
const r = checkConnection(
port({ id: 'a', relation: 'water', direction: 'out' }),
port({ id: 'b', relation: 'water', direction: 'out' }),
);
expect(r.ok).toBe(false);
expect(r.reason).toMatch(/Incompatible directions/);
});
it('same port to itself on one node: rejected', () => {
const p = port({ id: 'x' });
expect(checkConnection(p, p, { sameNode: true }).ok).toBe(false);
});
it('different ports of the same node may connect (self-loop)', () => {
const r = checkConnection(
port({ id: 'a', relation: 'heat', direction: 'out' }),
port({ id: 'b', relation: 'heat', direction: 'in' }),
{ sameNode: true },
);
expect(r.ok).toBe(true);
});
});