92 lines
3.0 KiB
TypeScript
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);
|
|
});
|
|
});
|