Files
Aislo/resources/tester/test_m02_structure_panel.py
T
eomsangdonandClaude Opus 5.5 cd824aca25 feat(spreadsheet): F 서버 재계산 · 산출근거 따로 저장 · M02 끼우기 · 금빛 시험
- common_util_spreadsheet_node.ts · common_util_spreadsheet.py · build:spreadsheet — [저장] 때 화면과 같은 TS 엔진을 Node 로 돌려 계산값 정본(브라우저 값 버림 · 못 풀면 503)
- M02 새 종류 basis — resources/master_template/basis/<열 id>.json(구조물집계표 열마다) · 층 복사 · 뼈대 검사 · 옛 구조물 문서 산출근거 49 벌 옮김(migrate_basis) · 새 열도 같이 만듦
- 상세 산출근거 카드 = 새 스프레드시트(import() 로 늦게 받음) · basis 읽기 · 저장
- ⚠ 임시 [스프레드시트 시험] 단추 — 빈 통합문서(시트 셋) · 저장 자리 tmp/spreadsheet_trial.json · 1단계 검증 뒤 지움
- 시험 resources/tester/spreadsheet/ — 저장 · 서버 다리 · 크기 예산 · M02 만 늦게 불러옴 · 실무 구조도 xlsx 세 벌 수식 2,699 칸 엑셀 캐시값 대조(엔진 빈 몸이면 건너뜀)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0168FQuoV7vDh5nhnSowW5cp
2026-09-27 20:12:39 +09:00

94 lines
3.8 KiB
Python

"""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"
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"),
[
(
"M02_MasterTemplete_Api_Fetch.ts",
["createStructure", "fetchStructureNumbers", "readTemplate", "saveTemplate"],
),
("M02_MasterTemplete_Drawing.ts", ["mountDrawingTemplate"]),
("../A00_Common/spreadsheet/spreadsheet.ts", ["createSpreadsheet"]),
],
)
def test_컨테이너가_쓰는_이름이_내보내진_것(source: str, names: list[str]):
"""도면 부품 · 스프레드시트(D) 가 이름을 바꾸면 여기서 먼저 걸림."""
body = _text(M02 / source)
panel = _text(PANEL)
for name in names:
assert re.search(rf"export (const|function|interface) {name}\b", body), f"{source}:{name}"
assert name in panel, 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"]