"""M02 구조물 명세 이름 고치기(`M02_SO_Def_Spec_Model.ts` · PLAN 52-11) 단위검증. Node 헬퍼(`helper_m02_so_def_spec.cjs`)가 TS 를 트랜스파일해 진짜 정의 사본(메모리)으로 돌리고 pytest 는 그 결과(JSON)를 판정. 못박는 것 - 배관 명세 나무: 컨테이너 5 · 항목 · 값 줄 · 이름 키 겹침 없음 · 필수/선택 · 꼴 표시. - 필수 컨테이너 제목은 정의 그룹 이름에 씀 · 항목 · 값 · 선택 컨테이너는 이름 표에 씀. - 이름만 바뀜 — types(옵션 · 키) 그대로 · 이름 표에 없는 키를 새로 만들지 않음. - 이름 표가 빈 종류는 명세 글로 읽음. - 정의 그룹 꼴(52-12): 그룹 제목 › 칸 › 선택지 · 제목 = 그룹 이름 · 칸 = 옵션 이름 · 선택지 = 이름 표(값 그대로) · 칸 없는 종류는 줄 없음. """ from __future__ import annotations import json import subprocess from pathlib import Path import pytest HERE = Path(__file__).resolve().parent @pytest.fixture(scope="module") def r() -> dict: proc = subprocess.run( ["node", str(HERE / "helper_m02_so_def_spec.cjs")], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) def test_배관_나무(r) -> None: assert r["levels"][0] == 5 assert r["levels"][1] > 5 and r["levels"][2] > 10 assert r["unique"] is True assert r["pipeTitle"]["tag"] == "required" and r["pipeTitle"]["group"] == "grv6lny" assert r["optional"]["tag"] == "optional" and r["optional"]["group"] is None assert r["basinForm"]["label"] == "I형" and r["basinForm"]["key"] == "I" def test_이름_고침_자리(r) -> None: assert r["groupName"] == "관 본체" assert r["names"] == [None, "관 지름", "Ø800", "흙막이 더"] assert r["reread"] == ["관 본체", "관 지름", "Ø800", "흙막이 더"] def test_구조는_그대로(r) -> None: assert r["sameTypes"] is True and r["sameKeys"] is True def test_이름_표_없는_종류(r) -> None: assert r["bareLabel"] == "흙막이" assert r["bareGroup"] == "유입" def test_정의_그룹_꼴(r) -> None: assert r["udRows"] == [ [0, "#gcrossud", "맹암거"], [1, "culvert_height_m", "암거 높이"], [1, "culvert_slope_pct", "암거 경사"], ] assert r["udGroup"] == "맹암거 본체" and r["udLabel"] == "암거 높이 칸" assert r["sideHead"]["nameKey"] == "" and r["sideHead"]["level"] == 0 assert r["sideChoice"] == [2, "L형"] assert r["sideName"] == "L 모양" and r["sideReread"] == "L 모양" assert "L형" in r["sideChoices"] assert r["bareKind"] == 0