task(A4.5): migrate revcloud/hatch/measure tools to v2

This commit is contained in:
Agent Zero
2026-08-27 00:48:28 +02:00
parent af46f0028a
commit 464ddb91cc
5 changed files with 255 additions and 8 deletions
+88
View File
@@ -6,6 +6,7 @@
import { describe, it, expect, vi } from 'vitest';
import { lineTool, coreDrawingPlugin } from '../src/plugins/builtin/core-drawing';
import { selectTool, coreModifyPlugin } from '../src/plugins/builtin/core-modify';
import { coreMeasurePlugin } from '../src/plugins/builtin/core-measure';
import { coreAnnotatePlugin } from '../src/plugins/builtin/core-annotate';
import { CADDocument } from '../src/kernel/document/CADDocument';
import { createInMemoryDoc } from './helpers/inMemoryDoc';
@@ -260,6 +261,93 @@ describe('A4.4 pilot: annotate tools', () => {
});
});
describe('A4.5 pilot: revcloud tool', () => {
it('committet per ENTER ab 3 Punkten mit Legacy-Konvention arcHeight=8', () => {
const { ydoc } = createInMemoryDoc();
const doc = new CADDocument(ydoc);
const ctx = makeCtx({ doc });
const cloud = coreDrawingPlugin.tools!.find((t) => t.manifest.id === 'revcloud')!;
cloud.handlers.down!(pe(0, 0), ctx);
cloud.handlers.down!(pe(100, 0), ctx);
cloud.handlers.down!(pe(100, 50), ctx);
const kev = { key: 'Enter', preventDefault: () => {} } as unknown as KeyboardEvent;
const consumed = cloud.handlers.key!(kev, ctx);
expect(consumed).toBe(true);
const all = doc.getAllElements();
expect(all.length).toBe(1);
expect(all[0].type).toBe('revcloud');
expect((all[0].properties.points as Pt[]).length).toBe(3);
expect(all[0].properties.arcHeight).toBe(8); // Legacy-Konvention
expect(all[0].properties.fill).toBe('none');
expect(doc.undo()).toBe(true);
expect(doc.getAllElements().length).toBe(0);
});
});
describe('A4.5 pilot: measure tool', () => {
it('2 Klicks zeigen Distanz+Winkel im Status; erzeugt KEIN Element', () => {
const { ydoc } = createInMemoryDoc();
const doc = new CADDocument(ydoc);
const ctx = makeCtx({ doc });
const meas = coreMeasurePlugin.tools!.find((t) => t.manifest.id === 'measure')!;
meas.handlers.down!(pe(0, 0), ctx);
expect(ctx.statuses.some((s) => s.includes('Endpunkt'))).toBe(true);
meas.handlers.down!(pe(30, 40), ctx); // dist=50, angle≈53.13°
const last = ctx.statuses[ctx.statuses.length - 1];
expect(last).toContain('distance:');
expect(last).toContain('angle:');
expect(last).toContain('53.1'); // atan2(40,30)≈53.13°
// KernLegacy-Verhalten: Messung erzeugt kein Element
expect(doc.getAllElements().length).toBe(0);
});
});
describe('A4.5 pilot: hatch tool', () => {
it('setzt hatch-Properties via updateElement; undo macht rückgängig', () => {
const { ydoc } = createInMemoryDoc();
const doc = new CADDocument(ydoc);
// Seed-Rect im Doc, das beim hitTest zurückkommt:
const rectEl = { id: 'r1', type: 'rect', layerId: 'l', x: 50, y: 50, width: 10, height: 10, properties: {} } as unknown as CADElement;
doc.addElement(rectEl);
const bridge = {
getIds: () => [],
setIds: () => {},
hitTest: () => rectEl,
};
const ctx = makeCtx({ doc, selection: bridge, options: { hatchPattern: 'cross', hatchSpacing: 12 } });
const hatch = coreModifyPlugin.tools!.find((t) => t.manifest.id === 'hatch')!;
hatch.handlers.down!(pe(50, 50), ctx);
const updated = doc.getElement('r1')!;
expect(updated.properties.hatch).toBe(true);
expect(updated.properties.hatchPattern).toBe('cross'); // aus Options
expect(updated.properties.hatchSpacing).toBe(12);
expect(doc.undo()).toBe(true); // A2b-Update ist selbst Undo-Schritt
expect(doc.getElement('r1')!.properties.hatch).toBeUndefined();
});
it('lehnt offene Elementtypen (line) mit Hinweis ab', () => {
const { ydoc } = createInMemoryDoc();
const doc = new CADDocument(ydoc);
const lineEl = { id: 'l1', type: 'line', layerId: 'l', x: 0, y: 0, width: 5, height: 5, properties: { x1: 0, y1: 0, x2: 5, y2: 5 } } as unknown as CADElement;
doc.addElement(lineEl);
const bridge = { getIds: () => [], setIds: () => {}, hitTest: () => lineEl };
const ctx = makeCtx({ doc, selection: bridge });
const hatch = coreModifyPlugin.tools!.find((t) => t.manifest.id === 'hatch')!;
hatch.handlers.down!(pe(2, 2), ctx);
expect(doc.getElement('l1')!.properties.hatch).toBeUndefined(); // nichts geändert
expect(ctx.statuses.some((s) => s.includes('rect/circle/polygon'))).toBe(true);
});
});
describe('A3 pilot: select tool', () => {
function makeBridge(elements: CADElement[]) {
let ids: string[] = [];