import { Point } from '@flatten-js/core'; import { beforeEach, describe, expect, it } from 'vitest'; import { createActor } from 'xstate'; import { LineEntity } from '../entities/LineEntity.ts'; import { getEntities, resetUndoBaseline, setEntities, setSelectedEntityIds, undo, } from '../state.ts'; import { ScaleState, scaleToolStateMachine } from './scale-tool.ts'; import { ActorEvent } from './tool.types.ts'; const ends = (index: number) => { const line = getEntities()[index] as LineEntity; const a = line.getStartPoint(); const b = line.getEndPoint(); return [a.x, a.y, b.x, b.y]; }; /** 기준점 (2,0) 클릭까지 — 선 A(0,0)-(10,0) 고름 · 선 B(0,5)-(4,5) 는 그대로 둘 것 */ function startAtBasePoint() { const a = new LineEntity('layer1', new Point(0, 0), new Point(10, 0)); const b = new LineEntity('layer1', new Point(0, 5), new Point(4, 5)); setEntities([a, b]); resetUndoBaseline(); setSelectedEntityIds([a.id]); const actor = createActor(scaleToolStateMachine).start(); expect(actor.getSnapshot().value).toBe(ScaleState.WAITING_FOR_BASE_VECTOR_START_POINT); actor.send({ type: ActorEvent.MOUSE_CLICK, worldMouseLocation: new Point(2, 0), screenMouseLocation: new Point(0, 0), holdingCtrl: false, holdingShift: false, }); expect(actor.getSnapshot().value).toBe(ScaleState.WAITING_FOR_BASE_VECTOR_END_POINT); return { actor, a, b }; } const typeNumber = (actor: ReturnType['actor'], value: number) => actor.send({ type: ActorEvent.NUMBER_INPUT, value, worldMouseLocation: new Point(99, 99) }); describe('축척 — 기준점 + 숫자 배율 (226-1)', () => { beforeEach(() => setSelectedEntityIds([])); it('배율 2 = 기준점 고정 두 배 · 다른 객체 · 순서 그대로', () => { const { actor, a, b } = startAtBasePoint(); typeNumber(actor, 2); // (0,0)→(-2,0) · (10,0)→(18,0) — 기준점 (2,0) 은 그대로 expect(ends(0)).toEqual([-2, 0, 18, 0]); expect(getEntities()[0].id).toBe(a.id); expect(getEntities()[1]).toBe(b); expect(ends(1)).toEqual([0, 5, 4, 5]); // 끝나면 선택 풀고 다음 고르기로 expect(actor.getSnapshot().value).toBe(ScaleState.WAITING_FOR_SELECTION); }); it('배율 0.5 = 절반', () => { const { actor } = startAtBasePoint(); typeNumber(actor, 0.5); expect(ends(0)).toEqual([1, 0, 6, 0]); }); it('되돌리기 한 번에 원래 자리', () => { const { actor } = startAtBasePoint(); typeNumber(actor, 2); undo(); expect(ends(0)).toEqual([0, 0, 10, 0]); expect(getEntities()).toHaveLength(2); }); it('Esc = 취소 — 객체 그대로', () => { const { actor, a, b } = startAtBasePoint(); actor.send({ type: ActorEvent.ESC }); expect(getEntities()).toEqual([a, b]); expect(ends(0)).toEqual([0, 0, 10, 0]); typeNumber(actor, 2); expect(ends(0)).toEqual([0, 0, 10, 0]); }); it('배율 0 은 받지 않음', () => { const { actor } = startAtBasePoint(); typeNumber(actor, 0); expect(ends(0)).toEqual([0, 0, 10, 0]); expect(actor.getSnapshot().value).toBe(ScaleState.WAITING_FOR_BASE_VECTOR_END_POINT); }); });