"""M02 구조물 설계 컨테이너(`M02_MasterTemplete_Structure.ts`) 붙는 자리 시험. 화면 조작은 ORCA 로 봄 — 여기서는 창끼리 계약이 안 어긋나는지만 봄. · 집계표 이름이 서버(`STRUCTURE_TABLE`)와 같은 글인가 · 컨테이너가 쓰는 이름(표 부품 · 도면 부품 · 서버 호출)이 정말 내보내진 것인가 · 열 머리 글 잇기(`columnHead`)를 Node 로 바로 돌려 봄 """ from __future__ import annotations import json import re import shutil import subprocess from pathlib import Path import pytest from M02_MasterTemplete import M02_MasterTemplete_Store as store ROOT = Path(__file__).resolve().parents[2] M02 = ROOT / "M02_MasterTemplete" PANEL = M02 / "M02_MasterTemplete_Structure.ts" MAIN = M02 / "M02_MasterTemplete_UI_Main.ts" SIDE = M02 / "M02_MasterTemplete_UI_Side.ts" def _text(path: Path) -> str: return path.read_text(encoding="utf-8") def test_집계표_이름이_서버와_같음(): found = re.search(r'STRUCTURE_TABLE = "([^"]+)"', _text(PANEL)) assert found and found.group(1) == store.STRUCTURE_TABLE def test_소스가_700줄을_넘지_않음(): for path in (PANEL, MAIN, M02 / "M02_MasterTemplete_Structure.css"): assert len(_text(path).splitlines()) <= 700, path.name @pytest.mark.parametrize( ("source", "names", "target"), [ ( "M02_MasterTemplete_Api_Fetch.ts", ["createStructure", "fetchStructureNumbers", "readTemplate"], PANEL, ), # 산출근거 저장은 컨테이너가 안 함 — [산출근거 수정] 이 여는 메인 칸 전체 편집이 함 ("M02_MasterTemplete_Api_Fetch.ts", ["saveTemplate"], MAIN), # 좌측 산출근거 줄 번호는 좌측 패널이 받음(구조물 도면 줄과 같은 자리) ("M02_MasterTemplete_Api_Fetch.ts", ["fetchBasisNumbers"], SIDE), ("M02_MasterTemplete_Drawing.ts", ["mountDrawingTemplate"], PANEL), ("../A00_Common/spreadsheet/spreadsheet.ts", ["createSpreadsheet"], PANEL), ], ) def test_컨테이너가_쓰는_이름이_내보내진_것(source: str, names: list[str], target: Path): """도면 부품 · 스프레드시트(D) 가 이름을 바꾸면 여기서 먼저 걸림.""" body = _text(M02 / source) used = _text(target) for name in names: assert re.search(rf"export (const|function|interface) {name}\b", body), f"{source}:{name}" assert name in used, name def test_집계표만_컨테이너를_붙임(): """다른 표 양식에는 안 붙음 — 시스템 층 · 이름이 집계표일 때만.""" body = _text(MAIN) assert 'at.layer === "system" && at.name === STRUCTURE_TABLE ? buildPanel() : null' in body # 구조물 도면 저장은 `도면` 칸만 갈아 끼움 — 도번 · 산출근거는 읽은 그대로 assert '{ ...(loaded as StructureDoc), 도면: edited as StructureDoc["도면"] }' in body @pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음") def test_열_머리_글_잇기(): """`columnHead` — 빈 층은 건너뛰고 ` · ` 로 이음 · 다 비면 열 id.""" found = re.search(r"^export const columnHead[\s\S]*?;$", _text(PANEL), re.M) assert found, "columnHead 를 못 찾음" # 부품 파일은 화면 모듈을 부르므로 통째로 못 싣음 — 그 함수만 떼어 Node 가 타입을 벗겨 돌림 script = ( "interface StructureColumn { id: string; 머리: (string | null)[] }\n" + found.group(0).replace("export ", "") + "\nconsole.log(JSON.stringify(process.argv.slice(1)" + ".map((a) => columnHead(JSON.parse(a)))));" ) cases = [ {"id": "pv_l", "머리": ["콘크리트포장", "T=(두께별)", "L"]}, {"id": "no", "머리": ["NO", None, None]}, {"id": "etc", "머리": [None, " ", None]}, ] result = subprocess.run( ["node", "--experimental-strip-types", "--no-warnings", "--input-type=module-typescript", "-e", script, *[json.dumps(c, ensure_ascii=False) for c in cases]], capture_output=True, text=True, encoding="utf-8", timeout=60, ) # fmt: skip assert result.returncode == 0, result.stderr assert json.loads(result.stdout) == ["콘크리트포장 · T=(두께별) · L", "NO", "etc"]