import { describe, expect, it } from 'vitest'; import { choose, defaultSummary, isSelectable, SHAPE_GROUPS, type MemberId } from '../src/core/shape-options'; const MEMBERS: MemberId[] = ['bearing', 'coping', 'column', 'footing', 'ground']; describe('형상 선택지 (spec §5.2, plan C5)', () => { it('every group has exactly one default, and it is the 1단계 model', () => { for (const m of MEMBERS) { for (const g of SHAPE_GROUPS[m]) { expect(g.options.filter((o) => o.isDefault)).toHaveLength(1); } } expect(defaultSummary('coping')).toBe('직각 · 직선'); expect(defaultSummary('column')).toBe('원형 · 중실'); expect(defaultSummary('footing')).toBe('직사각 · 없음 · 강관 · 없음'); expect(defaultSummary('ground')).toBe('육상'); }); it('defaults and confirmed options are selectable (하상, 승인 2026-10-26); every other option is refused with the reason', () => { for (const m of MEMBERS) { SHAPE_GROUPS[m].forEach((g, gi) => { for (const o of g.options) { if (o.isDefault || o.confirmed) { expect(choose(m, gi, o.label)).toBe(o.label); } else { expect(isSelectable(o)).toBe(false); expect(() => choose(m, gi, o.label)).toThrow('규칙 미정'); } } }); } }); it('an unknown option is refused', () => { expect(() => choose('coping', 0, '없는선택')).toThrow('알 수 없는'); }); }); it('하상 and 해상 are confirmed ground options (승인 2026-10-26); 육상 is the default', () => { const ground = SHAPE_GROUPS.ground[0].options; expect(ground.find((o) => o.label === '하상')!.confirmed).toBe(true); expect(ground.find((o) => o.label === '해상')!.confirmed).toBe(true); expect(choose('ground', 0, '해상')).toBe('해상'); });