Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TNMXVCZXMpHpVvqmFkeChL
90 lines
3.0 KiB
TypeScript
90 lines
3.0 KiB
TypeScript
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<typeof startAtBasePoint>['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);
|
|
});
|
|
});
|