175 lines
6.1 KiB
TypeScript
175 lines
6.1 KiB
TypeScript
/**
|
||
* elementToPrimitives Tests (Task C2).
|
||
* Deckt alle unterstützten Typen + Legacy-Konventionen + Grenzfälle ab.
|
||
*/
|
||
import { describe, it, expect } from 'vitest';
|
||
import { elementToPrimitives } from '../src/render/pixi/elementDrawers';
|
||
import type { CADElement } from '../src/types/cad.types';
|
||
|
||
function el(id: string, type: string, props: Record<string, unknown> = {}, geom: Partial<CADElement> = {}): CADElement {
|
||
return {
|
||
id,
|
||
type,
|
||
layerId: 'l',
|
||
x: 0,
|
||
y: 0,
|
||
width: 10,
|
||
height: 10,
|
||
properties: props,
|
||
...geom,
|
||
} as unknown as CADElement;
|
||
}
|
||
|
||
describe('elementToPrimitives', () => {
|
||
it('line: aus properties.x1..y2 mit stroke/sw', () => {
|
||
const prims = elementToPrimitives(el('l', 'line', {
|
||
x1: 0, y1: 0, x2: 100, y2: 50, stroke: '#f00', strokeWidth: 3,
|
||
}));
|
||
expect(prims.length).toBe(1);
|
||
expect(prims[0]).toEqual({
|
||
kind: 'line', from: { x: 0, y: 0 }, to: { x: 100, y: 50 },
|
||
stroke: '#f00', strokeWidth: 3,
|
||
});
|
||
});
|
||
|
||
it('line ohne Koordinaten ergibt leere Liste', () => {
|
||
expect(elementToPrimitives(el('l', 'line', {}))).toEqual([]);
|
||
});
|
||
|
||
it('rect: x/y ist Zentrum der BBox (Legacy-Konvention)', () => {
|
||
const prims = elementToPrimitives(el('r', 'rect', { fill: '#123456' }, {
|
||
x: 100, y: 50, width: 80, height: 40,
|
||
}));
|
||
expect(prims.length).toBe(1);
|
||
const p = prims[0];
|
||
if (p.kind !== 'rect') throw new Error('erwartete rect');
|
||
expect(p.x).toBe(60); // 100 − 40
|
||
expect(p.y).toBe(30); // 50 − 20
|
||
expect(p.w).toBe(80);
|
||
expect(p.h).toBe(40);
|
||
expect(p.fill).toBe('#123456');
|
||
});
|
||
|
||
it('rect fill none wird zu null', () => {
|
||
const prims = elementToPrimitives(el('r', 'rect', { fill: 'none' }));
|
||
const p = prims[0];
|
||
if (p.kind !== 'rect') throw new Error('erwartete rect');
|
||
expect(p.fill).toBeNull();
|
||
});
|
||
|
||
it('circle: radius mit Fallback width/2', () => {
|
||
const withExplicit = elementToPrimitives(el('c', 'circle', { radius: 25, fill: '#abcdef' }, { x: 5, y: 5 }));
|
||
const p = withExplicit[0];
|
||
if (p.kind !== 'circle') throw new Error('erwartete circle');
|
||
expect(p.radius).toBe(25);
|
||
expect(p.center).toEqual({ x: 5, y: 5 });
|
||
expect(p.fill).toBe('#abcdef');
|
||
|
||
const byWidth = elementToPrimitives(el('c', 'circle', {}, { width: 120 }));
|
||
const pb = byWidth[0];
|
||
if (pb.kind !== 'circle') throw new Error('erwartete circle');
|
||
expect(pb.radius).toBe(60); // fallback
|
||
});
|
||
|
||
it('arc: Winkel in Grad wie Legacy', () => {
|
||
const prims = elementToPrimitives(el('a', 'arc', {
|
||
radius: 40, startAngle: 0, endAngle: 90,
|
||
}, { x: 0, y: 0 }));
|
||
const p = prims[0];
|
||
if (p.kind !== 'arc') throw new Error('erwartete arc');
|
||
expect(p.startDeg).toBe(0);
|
||
expect(p.endDeg).toBe(90);
|
||
expect(p.radius).toBe(40);
|
||
});
|
||
|
||
it('polyline/polygon: points-Array, close je nach Typ', () => {
|
||
const pts = [{ x: 0, y: 0 }, { x: 10, y: 0 }, { x: 10, y: 10 }];
|
||
const open = elementToPrimitives(el('pl', 'polyline', { points: pts }));
|
||
const closed = elementToPrimitives(el('pg', 'polygon', { points: pts }));
|
||
expect(open.length).toBe(1);
|
||
expect(closed.length).toBe(1);
|
||
if (open[0].kind !== 'polyline' || closed[0].kind !== 'polyline') {
|
||
throw new Error('erwartete polyline');
|
||
}
|
||
expect(open[0].close).toBe(false);
|
||
expect(closed[0].close).toBe(true);
|
||
});
|
||
|
||
it('text: leer nicht gerendert; gefuellt mit fontSize/color', () => {
|
||
expect(elementToPrimitives(el('t', 'text', { text: '' }))).toEqual([]);
|
||
|
||
const filled = elementToPrimitives(el('t', 'text', {
|
||
text: 'Bühne A', fontSize: 18, color: '#ffffff',
|
||
}, { x: 50, y: 75 }));
|
||
expect(filled.length).toBe(1);
|
||
const p = filled[0];
|
||
if (p.kind !== 'text') throw new Error('erwartete text');
|
||
expect(p.text).toBe('Bühne A');
|
||
expect(p.fontSize).toBe(18);
|
||
expect(p.color).toBe('#ffffff');
|
||
});
|
||
|
||
it('unbekannter Typ ergibt leere Liste (renderer-sicher)', () => {
|
||
expect(elementToPrimitives(el('x', 'definitely-unknown'))).toEqual([]);
|
||
});
|
||
|
||
it('dimension: Linie + Label aus value/text', () => {
|
||
const prims = elementToPrimitives(el('d', 'dimension', {
|
||
x1: 0, y1: 0, x2: 100, y2: 0, value: '250 cm',
|
||
}, { x: 50, y: 0 }));
|
||
expect(prims.length).toBe(2);
|
||
expect(prims[0].kind).toBe('line');
|
||
const txt = prims[1];
|
||
if (txt.kind !== 'text') throw new Error('erwartete text');
|
||
expect(txt.text).toBe('250 cm');
|
||
});
|
||
|
||
it('leader: Linie + Label am Ende', () => {
|
||
const prims = elementToPrimitives(el('ld', 'leader', {
|
||
x1: 10, y1: 10, x2: 80, y2: 60, text: 'A1', fontSize: 14,
|
||
}));
|
||
expect(prims.length).toBe(2);
|
||
expect(prims[0].kind).toBe('line');
|
||
const txt = prims[1];
|
||
if (txt.kind !== 'text') throw new Error('erwartete text');
|
||
expect(txt.text).toBe('A1');
|
||
expect(txt.fontSize).toBe(14);
|
||
});
|
||
|
||
it('revcloud: geschlossener Punktzug', () => {
|
||
const prims = elementToPrimitives(el('rc', 'revcloud', {
|
||
points: [{ x: 0, y: 0 }, { x: 50, y: 0 }, { x: 50, y: 30 }],
|
||
}));
|
||
expect(prims.length).toBe(1);
|
||
const p = prims[0];
|
||
if (p.kind !== 'polyline') throw new Error('erwartete polyline');
|
||
expect(p.close).toBe(true);
|
||
});
|
||
|
||
it('chair: gefuelltes Rechteck mit Fallback-Farbe', () => {
|
||
const prims = elementToPrimitives(el('ch', 'chair', {}, { x: 50, y: 50, width: 20, height: 20 }));
|
||
const p = prims[0];
|
||
if (p.kind !== 'rect') throw new Error('erwartete rect');
|
||
expect(p.fill).toBe('#4a90d9');
|
||
expect(p.x).toBe(40);
|
||
expect(p.y).toBe(40);
|
||
});
|
||
|
||
it('table: Kreis mit Fallback-Farbe und Radius aus width', () => {
|
||
const prims = elementToPrimitives(el('tb', 'table', {}, { x: 0, y: 0, width: 60, height: 60 }));
|
||
const p = prims[0];
|
||
if (p.kind !== 'circle') throw new Error('erwartete circle');
|
||
expect(p.radius).toBe(30);
|
||
expect(p.fill).toBe('#8b7355');
|
||
});
|
||
|
||
it('stage: dunkles Rechteck', () => {
|
||
const prims = elementToPrimitives(el('st', 'stage', {}, { x: 0, y: 0, width: 200, height: 100 }));
|
||
const p = prims[0];
|
||
if (p.kind !== 'rect') throw new Error('erwartete rect');
|
||
expect(p.fill).toBe('#3a3a4a');
|
||
expect(p.w).toBe(200);
|
||
expect(p.h).toBe(100);
|
||
});
|
||
});
|