105 lines
4.3 KiB
TypeScript
105 lines
4.3 KiB
TypeScript
/**
|
|
* Task D12 - BlockAttribute: attrDefs + attrValues + Rendering.
|
|
*
|
|
* BlockDefinition.attrDefs[]: definiert Attribut-Slots (tag/prompt/
|
|
* default). Instanz (block_instance) traegt attrValues. Der Render-
|
|
* Adapter (elementToPrimitives) zeichnet die Attr-Werte als Text-
|
|
* Primitive an der Instanz-Position.
|
|
*/
|
|
import { describe, it, expect } from 'vitest';
|
|
import { CADDocument } from '../src/kernel/document/CADDocument';
|
|
import { createInMemoryDoc } from './helpers/inMemoryDoc';
|
|
import { elementToPrimitives } from '../src/render/pixi/elementDrawers';
|
|
import type { CADElement, BlockDefinition } from '../src/types/cad.types';
|
|
|
|
const BLOCK: BlockDefinition = {
|
|
id: 'blk-1',
|
|
name: 'Titelblock',
|
|
description: '',
|
|
category: 'frame',
|
|
elements: [],
|
|
attrDefs: [
|
|
{ tag: 'PROJEKT', prompt: 'Projektname', defaultValue: 'Unbenannt' },
|
|
{ tag: 'AUTOR', prompt: 'Bearbeiter', defaultValue: 'WebCAD' },
|
|
],
|
|
};
|
|
|
|
function instance(attrValues: Record<string, string>): CADElement {
|
|
return {
|
|
id: 'inst-1', type: 'block_instance', layerId: 'layer-0',
|
|
x: 100, y: 100, width: 0, height: 0,
|
|
properties: { blockId: 'blk-1', scale: 1, attrValues },
|
|
} as unknown as CADElement;
|
|
}
|
|
|
|
// ─── Typ-Ebene: attrDefs auf BlockDefinition ────────────────
|
|
|
|
describe('D12: BlockDefinition.attrDefs', () => {
|
|
it('attrDefs-Feld existiert mit tag/prompt/defaultValue', () => {
|
|
expect(BLOCK.attrDefs).toBeDefined();
|
|
expect(BLOCK.attrDefs!.length).toBe(2);
|
|
expect(BLOCK.attrDefs![0].tag).toBe('PROJEKT');
|
|
expect(BLOCK.attrDefs![0].prompt).toBe('Projektname');
|
|
expect(BLOCK.attrDefs![0].defaultValue).toBe('Unbenannt');
|
|
});
|
|
|
|
it('CADDocument speichert Block mit attrDefs (getBlock liefert sie zurueck)', () => {
|
|
const { ydoc } = createInMemoryDoc();
|
|
const doc = new CADDocument(ydoc);
|
|
doc.addBlock(BLOCK);
|
|
const loaded = doc.getBlock('blk-1');
|
|
expect(loaded!.attrDefs).toHaveLength(2);
|
|
expect(loaded!.attrDefs![1].tag).toBe('AUTOR');
|
|
});
|
|
});
|
|
|
|
// ─── Rendering: elementToPrimitives mit attrDefs ────────────
|
|
|
|
describe('D12: RenderAdapter zeichnet Attr-Texte', () => {
|
|
it('Instanz mit attrValues erzeugt text-Primitives pro Attribut', () => {
|
|
const el = instance({ PROJEKT: 'Halle A', AUTOR: 'L. Admin' });
|
|
const prims = elementToPrimitives(el, BLOCK.attrDefs);
|
|
const texts = prims.filter((p) => p.kind === 'text');
|
|
expect(texts).toHaveLength(2);
|
|
const proj = texts.find((t) => (t as { text: string }).text.includes('PROJEKT'));
|
|
expect(proj).toBeDefined();
|
|
expect((proj as { text: string }).text).toContain('Halle A');
|
|
const autor = texts.find((t) => (t as { text: string }).text.includes('AUTOR'));
|
|
expect((autor as { text: string }).text).toContain('L. Admin');
|
|
});
|
|
|
|
it('Fehlender Wert faellt auf attrDefs.defaultValue zurueck', () => {
|
|
const el = instance({});
|
|
const prims = elementToPrimitives(el, BLOCK.attrDefs);
|
|
const texts = prims.filter((p) => p.kind === 'text');
|
|
const proj = texts.find((t) => (t as { text: string }).text.includes('PROJEKT'));
|
|
expect((proj as { text: string }).text).toContain('Unbenannt');
|
|
});
|
|
|
|
it('Ohne attrDefs-Parameter: kein Attr-Text-Rendering (abwaertskompatibel)', () => {
|
|
const el = instance({ PROJEKT: 'Halle A' });
|
|
const prims = elementToPrimitives(el);
|
|
expect(prims.filter((p) => p.kind === 'text')).toHaveLength(0);
|
|
});
|
|
|
|
it('Instanz ohne attrValues mit attrDefs: defaults werden gezeichnet', () => {
|
|
const el: CADElement = {
|
|
id: 'inst-2', type: 'block_instance', layerId: 'layer-0',
|
|
x: 0, y: 0, width: 0, height: 0,
|
|
properties: { blockId: 'blk-1', scale: 1 },
|
|
} as unknown as CADElement;
|
|
const prims = elementToPrimitives(el, BLOCK.attrDefs);
|
|
const texts = prims.filter((p) => p.kind === 'text');
|
|
expect(texts).toHaveLength(2);
|
|
});
|
|
|
|
it('Text-Positionen gestaffelt unterhalb der Instanz-Position', () => {
|
|
const el = instance({ PROJEKT: 'A', AUTOR: 'B' });
|
|
const prims = elementToPrimitives(el, BLOCK.attrDefs);
|
|
const texts = prims.filter((p) => p.kind === 'text') as Array<{ kind: 'text'; at: { x: number; y: number }; text: string }>;
|
|
expect(texts[0].at.x).toBe(100);
|
|
expect(texts[0].at.y).toBeCloseTo(100 - 8, 0);
|
|
expect(texts[1].at.y).toBeLessThan(texts[0].at.y);
|
|
});
|
|
});
|